What is the official way of checking that opening a file succeeded?

J

Juha Nieminen

Consider this:

int main()
{
std::ifstream is("file1");
if(is.good())
{
std::cout << "ok\n";
std::string line;
while(std::getline(is, line));
is.close();
}

is.open("file2");
if(!is.good())
{
std::cout << "failed!\n";
}
}

Assume that both files exist and are normally readable. With gcc the
"failed!" output is not triggered, while with MSVC++ 2005 it is
triggered. (errno points to "no error" in this case, so the file was
clearly opened successfully, but the good() bit was not set.)

I can only assume one of two things. Either

1) good() is *not* the proper way of checking if opening a file
succeeded, or

2) there's a bug in MSVC++ 2005.

Comments?
 
B

Bo Persson

Juha said:
Consider this:

int main()
{
std::ifstream is("file1");
if(is.good())
{
std::cout << "ok\n";
std::string line;
while(std::getline(is, line));
is.close();
}

is.open("file2");
if(!is.good())
{
std::cout << "failed!\n";
}
}

Assume that both files exist and are normally readable. With gcc
the "failed!" output is not triggered, while with MSVC++ 2005 it is
triggered. (errno points to "no error" in this case, so the file was
clearly opened successfully, but the good() bit was not set.)

I can only assume one of two things. Either

1) good() is *not* the proper way of checking if opening a file
succeeded, or

2) there's a bug in MSVC++ 2005.

Comments?

1) One way of checking the result of open, is to look at the return
value of open(). :)

std::ifstream is:

if (is.open("file1"))
do_something();
else
failure();


2) When re-opening a stream, the original standard didn't say what
should happen to the flags.

After long considerations, the standards committee decided that this
means that they should be kept unchanged.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2822.html#22

Here, this means that the eof() flag from getline() is still set after
opening file2. To clear that, you have to call is.clear().


While producing the next standard (C++ 2010?), the committee has now
changed its mind, and believe that it is a good idea to let open()
call the clear() function for you. It seems like people are getting
confused that it doesn't do so already. :)


So, VC 2005 actually follows the current language standard, while gcc
might have already started to implement features of the next standard.
If you do call clear(), like you are supposed to, you will not notice
this difference!



BTW, there is no "good bit", so good() is just the absence of status
bits (bad, fail, or eof).



Bo Persson
 
J

James Kanze

good() is definitely not the proper way of checking if opening a
file succeeded, or much of anything else. (In fact, I've never
found a correct use for ios::good().) I tend to use is_open(),
because it says explicitly what I'm asking, but fail() or simply
treating the stream as a boolean are also valid options; the
last is probably the most idiomatic, e.g.:

std::ifstream is( "file1" ) ;
if ( ! is ) {
// open failed...
}
1) One way of checking the result of open, is to look at the return
value of open(). :)

Not for his first test, where the open was embedded in the
constructor. (Constructors don't have return values.)
std::ifstream is:
if (is.open("file1"))
do_something();
else
failure();
2) When re-opening a stream, the original standard didn't say
what should happen to the flags.

Actually, it did. It said that they would be unchanged. This
is obviously an error (and as you say, has been corrected), but
formally, a compiler which does anything else today is not
conform.
After long considerations, the standards committee decided
that this means that they should be kept unchanged.

Here, this means that the eof() flag from getline() is still
set after opening file2. To clear that, you have to call
is.clear().

Note that if the file is empty, eof() might be set (or might
not---it's unspecified) immediately after the open.
While producing the next standard (C++ 2010?), the committee
has now changed its mind, and believe that it is a good idea
to let open() call the clear() function for you. It seems like
people are getting confused that it doesn't do so already.
:)
So, VC 2005 actually follows the current language standard,
while gcc might have already started to implement features of
the next standard. If you do call clear(), like you are
supposed to, you will not notice this difference!
BTW, there is no "good bit", so good() is just the absence of
status bits (bad, fail, or eof).

And you don't want to check eof, so good() is NOT the function
you want.
 
J

Juha Nieminen

James said:
good() is definitely not the proper way of checking if opening a
file succeeded, or much of anything else. (In fact, I've never
found a correct use for ios::good().) I tend to use is_open(),
because it says explicitly what I'm asking, but fail() or simply
treating the stream as a boolean are also valid options; the
last is probably the most idiomatic, e.g.:

std::ifstream is( "file1" ) ;
if ( ! is ) {
// open failed...
}

I thought the operator bool() for streams returns the value of good(),
so it would be completely equivalent.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,044
Latest member
RonaldNen

Latest Threads

Top