LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 03-25-2009, 07:54 PM   #1
Fredstar
Member
 
Registered: Jul 2004
Location: Rochester, NY
Distribution: Fedora9::FreeBSD7.1
Posts: 296

Rep: Reputation: 30
c++ returning refrence to ifstream


Hi All,
Since everyone was so helpful last time i figured i would try you for another question.

In java if i want to return an input stream i could just do something like this.

Code:
FileReader openFile( String path ){
 return new FileReader(path);
}
Now, im going for something similar in c++. I know that c++ would actually try to return a copy of the ifstream instead of the object refrence which is what im going for. What i tried is.

Code:
ifstream& openFile ( char str[] );


ifstream& openFile ( char str[] )
{ 
 ifstream inFile;
 inFile.open(str);
 return inFile&;
}

int main()
{ 
 //Some random code to give str an actual value.
 ifstream inFile = openFile(str);
 return 0;
}
However, i cant get it to compile. Is my thought process on how to return a refrence to my ifstream correct?

Thanks in advance!
 
Old 03-25-2009, 09:20 PM   #2
Biddle
Member
 
Registered: Jan 2009
Posts: 37

Rep: Reputation: 17
Quote:
Is my thought process on how to return a refrence to my ifstream correct?
No you have an ampersand added to the ifstream which makes no sense in this situation and you can not return a reference to an instance which will go out of scope. If this was a constant reference then the life of the temporary would be extended but also become useless as it would be constant.
What exactly do you think this function gains you?
streams use RAII so your code could be written like
Code:
int main()
{ 
 //Some random code to give str an actual value.
 std::ifstream inFile(str);
}

Last edited by Biddle; 03-25-2009 at 09:22 PM. Reason: added link
 
Old 03-25-2009, 09:31 PM   #3
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by Fredstar View Post
In java if i want to return an input stream i could just
Java has a garbage collector, so it can use references the way C++ uses pointers without worrying about who does the delete.

In C++ if you want a function to return an object it allocated, the only direct approach is to return a pointer, not a reference.

Then the caller becomes responsible for ultimately deleting the object.

In many kinds of programming it is possible and worthwhile to have a much more structured relationship between the creation point of an object and its deletion point. Then it would be a violation of that structure to return a pointer to the function allocated object, so you're not left with good choices.

In other kinds of programming, you just recognize that object ownership issues are consistently part of the problem so you must be consistently careful with their solution.

I don't know the style nor structure of your project. So one answer is return by pointer and remember to delete later. But that may not be a good answer.
 
Old 03-25-2009, 09:33 PM   #4
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
(example for previous post)
Code:
ifstream* openFile ( char str[] );

ifstream* openFile ( char str[] )
{ 
 ifstream* inFile = new ifstream;
 inFile->open(str);
 return inFile;
}

int main()
{ 
 //Some random code to give str an actual value.
 ifstream* inFile = openFile(str);
...
 delete inFile;
 return 0;
}
But in many cases it makes sense to do something more like
Code:
void openFile ( ifstream& inFile, char str[] );

void openFile ( ifstream& inFile, char str[] )
{ 
 inFile->open(str);
}

int main()
{ 
 //Some random code to give str an actual value.
 ifstream inFile;
 openFile(inFile, str);
...
 return 0;
}

Last edited by johnsfine; 03-25-2009 at 09:58 PM.
 
Old 03-25-2009, 09:33 PM   #5
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
A better way to do it is to take a reference to std::ifstream, modify it, and return bool to indicate the result. Returning a new object comparably to the way Java does is often done with std::auto_ptr; however, that's a borderline-useless class because you can't even create a list of std::auto_ptr. If you're actually initializing an object with the return, you can return it by value and initialize with e.g. ifstream inFile( openFile(str) );, which will generally prevent copying the object because inFile in main is constructed where inFile in openFile was at the time openFile returns. These things are what Java hides from you; in reality, Java just creates a pointer to a new object wrapped with a shared pointer. For everything, except maybe integral types. That should generally be avoided in C++, especially when you know what you need at compile time (as is the case here.)
Kevin P. Barry

PS This looks like I'm responding to the others here, also; however, it just took me a long time to write my response and by the time I posted it, others had, also.

Last edited by ta0kira; 03-25-2009 at 09:36 PM.
 
Old 03-25-2009, 09:40 PM   #6
Biddle
Member
 
Registered: Jan 2009
Posts: 37

Rep: Reputation: 17
I find it hard to believe people are suggesting heap allocation or using a construct in place, when the stream object does not have a copy constructor as it makes no sense. Which copy would own the resource, which one should close it?
 
Old 03-25-2009, 09:54 PM   #7
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by Biddle View Post
I find it hard to believe people are suggesting heap allocation
What's the problem with heap allocation?

Quote:
or using a construct in place, when the stream object does not have a copy constructor
I've never had a good understanding of the rules in the standard for that one:

Object 1 is in local scope in a function. The function returns that object by value implying temporary object 2 created by copy constructor from object 1. That temporary is the input to the constructor of object 3, so a second call to the copy constructor copying 2 to 3?

Sometimes the compiler figures out to short circuit those two copy constructors and do it all with one object. When (if ever) must the compiler short circuit those copy constructors? When (if ever) may the compiler short circuit those copy constructors? If must doesn't equal may, that makes a very confusing features. If they do equal then the examples I've looked at are very confusing and/or compiler bugs. Either way, this is a construct I'd rather not use at all with any object with interesting construction.
 
Old 03-25-2009, 10:01 PM   #8
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by Biddle View Post
I find it hard to believe people are suggesting heap allocation or using a construct in place, when the stream object does not have a copy constructor as it makes no sense. Which copy would own the resource, which one should close it?
Yes, I don't often use std::ifstream so I forgot about the copy constructor. However, you're incorrect saying that it doesn't have one; it has one, but it's private. If it was public, however, it wouldn't be called with construct-in-place. The visibility alone causes it to fail.
Code:
//(compile with '-O0' just to make sure)

#include <stdio.h>


struct myclass
{
	myclass()
	{ fprintf(stderr, "construct\n"); }

	~myclass()
	{ fprintf(stderr, "destruct\n"); }

	//make this 'private' and it won't compile, but it's never called
	myclass(const myclass&)
	{ fprintf(stderr, "copy\n"); }
};


myclass copy_me()
{
	myclass temp;
	return temp;
}


int main()
{
	myclass one( copy_me() );
}
In this case, there should be no ambiguity about resources if no copy is made. In my own classes, I'd rather make a copy without resources than make a copy fail entirely. For example, when I write copy constructors for classes with mutexes, I initialize a new mutex in the lvalue but copy the remaining salient information. It wouldn't make sense to prevent copying of such an object. In OP's case, it would make perfect sense for std::ifstream to reopen the file in the lvalue, then close the file in the rvalue when it destructs; they won't interfere with each other if it does a dup and fdopen internally (inefficiency aside, that's very logical behavior.) The "problem" here is that standard C++ is for all systems; therefore, the lowest common denominator is to require that std::ifstream not be copyable.

What if someone wants a list of std::ifstream? Does it make sense to prevent that versatility because "somebody" (not you; the unspecified somebody) doesn't know what to do when something with resources is copied? The answer to the question of resources is as clear here as it is with dynamic memory (at least in the context of POSIX.) Shared memory, threads, mutexes, conditions, etc. are cases where it isn't as clear, but it isn't unreasonable to copy everything within a class except for those things; all one has to do is document the behavior.
Kevin Barry

PS This is one of the many reasons I always use C for I/O (except in OS-portable libraries.)

Last edited by ta0kira; 03-25-2009 at 11:14 PM.
 
Old 03-26-2009, 06:36 AM   #9
Biddle
Member
 
Registered: Jan 2009
Posts: 37

Rep: Reputation: 17
Quote:
What's the problem with heap allocation?
Well what does it gain in this instance? It extends the life of the temporary yes but it also introduces the possibility of a memory leak, when the class is intentionally designed to release resources on going out of scope. In addition the OP's code can be completed in a one liner, yet instead it is reimplementing the constructor.
Quote:
Sometimes the compiler figures out to short circuit those two copy constructors and do it all with one object. When (if ever) must the compiler short circuit those copy constructors? When (if ever) may the compiler short circuit those copy constructors?
Quote:
12.8
Whenever a temporary object is copied using a copy constructor, and this object and the copy have the same cv-unqualified type, an implementation is permitted to treat the original and the copy as two different ways of referring to the same object and not perform a copy at all, even if the copy constructor or destructor have side effects.
Note that as ta0kira pointed out and I meant to say (it was 3 am )
Quote:
A program is ill-formed if the copy constructor or the copy assignment operator for an object is implicitly used and the special member function is not accessible (clause 11).

Quote:
In this case, there should be no ambiguity about resources if no copy is made.
Yes but whether a copy is made is up to the implementation therefore it may or may not happen.

Quote:
In OP's case, it would make perfect sense for std::ifstream to reopen the file in the lvalue, then close the file in the rvalue when it destructs; they won't interfere with each other if it does a dup and fdopen internally (inefficiency aside, that's very logical behavior.) The "problem" here is that standard C++ is for all systems; therefore, the lowest common denominator is to require that std::ifstream not be copyable.
Just look at why the stream does not make available the copy constructor, they share global state. A stream is constructed and some data is written to it, then the stream is copied to another. Does the second stream share the same global state of the offsets that the first has? ie should reading from the second state start at offset zero or the first streams offset. Also look at writting to the stream.
 
Old 03-26-2009, 07:54 AM   #10
johnsfine
LQ Guru
 
Registered: Dec 2007
Distribution: Centos
Posts: 5,286

Rep: Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197Reputation: 1197
Quote:
Originally Posted by Biddle View Post
Well what does it gain in this instance?
I assumed the original post represented a greatly simplified example of what Fredstar actually wants to do.

In that example, there is no benefit to having the openFile function at all, vs. opening the file in the main function.

If the real code adds something that provides a reason to open the file in that function, then using the heap to allocate the ifstream object and returning it by pointer is the simple way to avoid significantly restructuring the code.
 
Old 03-26-2009, 10:07 AM   #11
ta0kira
Senior Member
 
Registered: Sep 2004
Distribution: FreeBSD 9.1, Kubuntu 12.10
Posts: 3,078

Rep: Reputation: Disabled
Quote:
Originally Posted by Biddle View Post
Just look at why the stream does not make available the copy constructor, they share global state. A stream is constructed and some data is written to it, then the stream is copied to another. Does the second stream share the same global state of the offsets that the first has? ie should reading from the second state start at offset zero or the first streams offset. Also look at writting to the stream.
Code:
FILE *rvalue_file = fopen("myfile", "a+");
FILE *lvalue_file = fdopen( dup( fileno(rvalue_file) ), "a" );
That's perfectly reasonable behavior (error checking and mode aside.) I use this pattern quite a bit to allow me to tabulate objects that use IPC, although 99% of the time the copy is made with a NULL file and I change it in place.
Kevin Barry

Again, if others will use it, all you need to do is document your solutions to ambiguity, e.g. buffering mode, stream position, etc.

Last edited by ta0kira; 03-26-2009 at 10:10 AM.
 
Old 03-27-2009, 04:56 PM   #12
Fredstar
Member
 
Registered: Jul 2004
Location: Rochester, NY
Distribution: Fedora9::FreeBSD7.1
Posts: 296

Original Poster
Rep: Reputation: 30
Hi All,

Sorry it has been so long since i was able to check in on this thread.

I want to say thanks to everyone for your input. I'm really new to c++ and have some bad habits, or just a few things i got really used to in java that i wont be able to do in c++.

Yes, the above post was a "very" slimmed version of what i was trying to do but realised that in c++ i could just pass reference to an already opened ifstream.

Example
Code:
void doSomethingWithStream ( ifstream& inFile );


void doSomethingWithStream ( ifstream& inFile ){
  while ( !inFile.eof() ){
    //do something
  }
}

int main(){
 ifstream inFile;
 inFile.open("someInfo.txt");
 doSomethingWithStream (inFile);
 return 0;

}
Again, thank you everyone. Even if your help was a little above my had it gives me a good picture as to what's ahead.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[C] Pass pointer of struct to function by refrence PJani Programming 3 11-19-2008 12:49 AM
Brief Refrence of DNS on web mohd anas Linux - Networking 1 11-08-2006 06:37 AM
error in assigning the iterator to refrence varaible ashwinipahuja Programming 1 06-18-2004 05:55 AM
Refrence book for newbie vcheah Linux - Newbie 1 12-19-2001 01:17 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:35 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration