Error with ifstream and exceptions

I

Ian Collins

Are you suggesting that because it is an OS extension that it is not
valid C++ code?
No.

You seem to imply it's wrong to use these Exceptions, what exactly is
the point you are trying to make here?

I'm not implying anything. I'm simply pointing out (for the third time)
there is no standard method for mapping hardware generated asynchronous
events to exceptions.
 
P

Paul

Ian Collins said:
I'm not implying anything. I'm simply pointing out (for the third time)
there is no standard method for mapping hardware generated asynchronous
events to exceptions.
What you seem to be trying to point out is that there is no ISO standard to
define the implementation of SEH.
Your original wording re: "that is an extension, not part of standard C++"
seemed to imply that is was non compliant code and therefore not C++.
 
I

Ian Collins

What you seem to be trying to point out is that there is no ISO standard
to define the implementation of SEH.
Your original wording re: "that is an extension, not part of standard
C++" seemed to imply that is was non compliant code and therefore not C++.

I haven't implied anything, my wording (in full) was:

"If the OS maps asynchronous events to exceptions, that is an extension,
not part of standard C++. Most platforms don't do it."

Followed up by:

"There is no standard method for mapping hardware generated asynchronous
events to exceptions."

Followed up by:

"I'm not implying anything. I'm simply pointing out (for the third time)
there is no standard method for mapping hardware generated asynchronous
events to exceptions."

No implications, just repetition of a simple fact.
 
J

James Kanze

* James Kanze, on 08.02.2011 02:03:
That's a very subjective opinion.

It depends. Not having the choice, and always using an
exception, is very bad software engineering. In the case of the
OP's code, it's also very bad software engineering. At the
other extreme, if you're opening some sort of configuration
file, installed with your executable, or a file with data you've
written earlier, then an exception is certainly appropriate
(unless you actually exit). In between, it's a gray area; you
wouldn't normally use exceptions when opening a file whose name
was user input, but I imagine that there are exceptions even
there.
When done properly, it can yield more clear and maintainable code.
I think possibly you're assuming a false dichotomy, that it's
either exception or possibility of checking result of open
attempt.

As with any error, its a tricotomy: you can abort, you can raise
an exception, or you can return an error code. (Actually, in
the case of input, you can also just continue; there are cases
where the correct handling of a missing file is to treat it as
if it were empty.)
With that as (incorrect) assumption you'd have to choose the
practically least evil.
But it isn't either/or, and it isn't necessary to force client
code to do needless check or force it to needlessly deal with
an exception.

Agreed. I was speaking very much in the context of the OP's
code. But such cases do seem to be the majority, at least in
beginning programmers' code.
 
J

James Kanze

(There are system libraries to catch signals, but those are
neither C++ nor standard.)

Just a nit, but the function to set up a signal handler is
standard C++ (by inclusion from C). What you can do in a signal
handler is very, very limited, however, and doesn't include
throwing an exception. (Specific operating systems may allow
a little bit more, but not usually very much.)
 
J

James Kanze

don't EVER? or almost never?

For text input, don't ever. For some very special cases of
binary input, it might be appropriate. But such cases will only
occur in very advanced programs.
EOF is not a 'failure', it's not only expected but guaranteed
to exist.

The standard says otherwise, and all compilers I've seen
implement this correctly. Trying to read beyond the end of file
results in failbit being set.
You try to encourage the OP to not use failbit but you are
wrong to suggest that this is the norm.

I'm not saying not to use failbit. I'm saying not to generate
an interrupt on failbit.
Even if it was the norm who gives a dam what the norm is , it
doesn't mean he needs to code this way.

Unless he wants his code to work.
This may be your practise, I don't see what anyone can gain
from ignoring failbit errors.

Who said anything about ignoring failbit? You don't seem to
understand English any better than you understand C++.
Hundreds of online examples use badbit or failbit masks, they
are not all wrong.

I've never seen an example which triggers an exception on
failbit.
 
M

Marco

Basically, I think you've misunderstood how IO works.

That's possible. C++ is new to me.
And when you've no more lines to read?

Then I expect this loop to end, and it does so as far as I tested.
In practice, the only thing you'd ever use exceptions for with
IO is badbit, which should be set in case of a hardware problem
(disk read error, etc.).

I really didn't want to start a war in this thread. I thought it is a basic
question with an easy answer, but unfortunately there is none. But I have the
feeling that I should drop the exceptions approach for a missing input file.
Obviously it's *not* bad practice just to check the ifstream in an if
statement. So I end up with this code:

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

int main() {
ifstream fileIn( "file" );
if ( !fileIn ) {
cout << "Error.\n" << endl;
// Some people are confused that the program does not exit on
// missing input file, so here it is.
return -1;}

string line;
while ( getline( fileIn, line ) ) {
cout << line << endl;
}

fileIn.close();
return 0;
}

I hope this is correct and not bad programming practice, correct me otherwise.
Anyway thanks for all your answers.


Regards
Marco
 
P

Paul

James Kanze said:
For text input, don't ever. For some very special cases of
binary input, it might be appropriate. But such cases will only
occur in very advanced programs.



The standard says otherwise, and all compilers I've seen
implement this correctly. Trying to read beyond the end of file
results in failbit being set.


I'm not saying not to use failbit. I'm saying not to generate
an interrupt on failbit.


Unless he wants his code to work.



Who said anything about ignoring failbit? You don't seem to
understand English any better than you understand C++.
Bollocks, you were unclear about what you were saying.
You commented on his exception mask with ...."you don't ever want exceptions
on failbit".
 
J

James Kanze

That's possible. C++ is new to me.
Then I expect this loop to end, and it does so as far as I tested.

Yes, but why? That's the heart of understanding C++ IO. It
ends because a call to getline fails, because there is no line
to get.

Basically, an istream maintains three "status" bits: badbit,
failbit and eofbit. In practice (regretfully), you can almost
forget about badbit, since most implementations will never set
it. (The intent is that it be set in cases of a "hard" error,
such as a read error on disk. In practice, most, if not all
implementations just treat this as if it were end of file.) The
most important status bit, in the first instance, is failbit; it
is set if the preceding read failed, either because there was no
data to read (end of file), or because the input had the wrong
format (impossible with getline, but if the input stream has
something like "abc" when you try to read an int). Finally,
eofbit is a bit tricky, because it represents internal status:
eofbit will be set anytime the implementation sees an end of
file, even when reading ahead. About the only time you check
eofbit is after a read failed: if the read failed and eofbit is
not set, then the input was incorrectly formatted; otherwise,
there's a good chance that you've reached the end of file.

Note that with getline on a string, there are only two possible
causes of error (beyond hardware read errors): you run out of
memory, or you reach end of file without seeing a new line, but
after having seen at least one character. In the first case,
badbit should be set (but it wouldn't surprise me if some
implementations let the bad_alloc exception leak out). In the
second, failbit gets set, but of course, end of file has been
seen internally, so eofbit is also set. Typically, this will
result in the last, incomplete line not being seen by the
program (and this is what will happen with your code if the
input file doesn't end with a newline character). If this is
not the behavior you want, then you need something like:

while ( getline( fileIn, line ) || fileIn.gcount() != 0 ) {
if ( !fileIn ) {
// incomplete last line...
}
// ...
}

Depending on context and what you are doing, this may or may not
be important.
I really didn't want to start a war in this thread.

You didn't. Obviously, opinions as to when to use exceptions
vary, but in fact, my response was very oriented to you, the
context of your posting, and you're apparent programming level
in C++; Ian probably summed it up best with his response to me:
you don't use exceptions for a missing file unless the fact that
it is missing is somehow exceptional. (Which of course begs the
point as to what is exceptional, but in a short program which
reads a more or less random file, the fact that the file isn't
there could hardly be considered exceptional.)
I thought it is a basic
question with an easy answer, but unfortunately there is none.

Nope. There are no easy answers:). C++ generally offers
several possible solutions to any problem, and the "best", or
even the "correct" solution, will depend on the context in which
the problem occurs.
But I have the feeling that I should drop the exceptions
approach for a missing input file.

For small programs which receive input data from a file,
definitely. For larger and more complex applications, it will
depend on the context: if the missing file is something that you
sort of expect from time to time (e.g. the filename was provided
by a user), exceptions probably aren't appropriate either; if
the missing file is part of your "system" (the deliverables
which should be installed together), or is a file that should
have been written by some other part of the application, an
exception is probably most appropriate, although rather than
playing around with the exception mask in the istream, I'd write
something like:

std::ifstream fileIn( name );
if ( !fileIn.open() )
throw ...
Obviously it's *not* bad practice just to check the ifstream in an if
statement. So I end up with this code:
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main() {
ifstream fileIn( "file" );
if ( !fileIn ) {
cout << "Error.\n" << endl;
// Some people are confused that the program does not exit on
// missing input file, so here it is.

Any error should result in an error return status, if there's
the slightest chance your program might be used in a script, and
with an error message on cerr (rather than cout) if there's the
slightest chance your program might be invoked on the command
line.
return -1;

The choice of -1 probably isn't optimal here. The only value
guaranteed to be treated as an error is EXIT_FAILURE; under Unix
and Windows, there is a tradition that errors are small positive
integers, and it is acceptable on these platforms to return
different small positive integers to distinguish between
different "errors". The Unix programs grep return 1 if they
don't find the string, for example, and 2 if they weren't able
to open the file.

(FWIW: under Unix, the return code will be coerced into an
unsigned char, thus -1 becomes 255. And the convention is that
errors from the program be in the range 1-127; error codes above
that are reserved for cases where the program has crashed.)
string line;
while ( getline( fileIn, line ) ) {
cout << line << endl;
}
fileIn.close();
return 0;

I hope this is correct and not bad programming practice,
correct me otherwise.

It's fine; my comments above are really nits (except maybe for
the case where the file doesn't end with a new line---if you're
on Windows, try entering "abc", and nothing else, in Notepad,
then save it and use it to test your program).

Another improvement that you'd want to make in production code:
before returning 0:
cout.flush();
if ( !cout )
// Write error in the output...
This is more important than closing the input (here, since the
input will be automatically closed when fileIn goes out of
scope). If for some reason (e.g. disk full) there has been
a write error, the output data will not be complete, and your
user should definitely be informed.
 
G

Goran

Just for the record, well written C++ programs don't use
exceptions for reporting an error when opening a file.

I disagree. It all depends on what needs to happen on such an error.

Here's an example using MFC (much hated and IMO not all that good, but
a very well established library):

CWinApp theApp;

void Process(const CString& s)
{
// Process baby, process.
}

void Delete(CException* p) { p->Delete(); }

int main(int, char*[])
{
try
{
if (!AfxWinInit:):GetModuleHandle(NULL), NULL, ::GetCommandLine(),
0))
AfxThrowResourceException();

CString s;
CStdioFile f("file.txt", CFile::modeRead).
while (f.ReadString(s))
Process(s);
}
catch(const CException* e)
{ // exception-safety elided for brevity.
e->ReportError();
e->Delete();
}
return 0;
}

Here, if there is a problem in accessing a file, program ends up with
"file.txt was not found", or, "Encountered a sharing violation while
accessing file.txt", or similar, on screen. That's not bad, not bad at
all.

It should be noted that, error-reporting wise, exception thrown from
CFile/CStdioFile constructor will be better than something __anyone
will come up with in 3 minutes of coding__. Why? Because failure modes
of this small piece are already many, and a library worth it's salt
__should__ emit errors containing a rather detailed error info for all
that (and amazingly, MFC does it).

In this particular case, exception thrown will be CFileException*,
containing "exception cause" number, system error number and a file
name. And, of course, exception object is capable of turning it's
contents into localized an error text, and a localized one at that.

And there's something else: some people argue that program should
offer a better user-friendly error explanation instead of saying
exactly what happened. Yes, but that is __hard__. That is hard,
because code needs to know up-front about a likely failure reason, and
it needs to check whether actual failure indeed was caused by that,
and only in that case a better, user-friendly message is OK (and even
then, original error cause should probably remain). Otherwise said
message might be completely unhelpful, because guess was wrong and
real failure cause was omitted. I think we have all seen this in the
wild, numerous times.

tl;dr: if error info, both "programmatic" and "user-friendly", is
competent, there's nothing wrong in using exceptions even for resource
(like a file object) creation problems. IMO, your idea that you need
error-return for that is caused more by incompetent error reporting in
existing libraries, than by some inherent problem in handling such
failures with exceptions.

Goran.
 
P

Paul

James Kanze said:
Yes, but why? That's the heart of understanding C++ IO. It
ends because a call to getline fails, because there is no line
to get.

Basically, an istream maintains three "status" bits: badbit,
failbit and eofbit. In practice (regretfully), you can almost
forget about badbit, since most implementations will never set
it. (The intent is that it be set in cases of a "hard" error,
such as a read error on disk. In practice, most, if not all
implementations just treat this as if it were end of file.) The
most important status bit, in the first instance, is failbit; it
is set if the preceding read failed, either because there was no
data to read (end of file), or because the input had the wrong
format (impossible with getline, but if the input stream has
something like "abc" when you try to read an int).

I cannot ignore this inconsistency, have you taken any medication today
James?
I refer to your other post in this thread re:

"In practice, the only thing you'd ever use exceptions for with
IO is badbit, which should be set in case of a hardware problem
(disk read error, etc.)."
and
"I've never seen an example which triggers an exception on
failbit."

What the hell man, this seems to define a whole new level of inconsistency.
10 out of 10 for effort though as it also seems to define a new level of
long postings. :)

<snip rest>
 
P

Paul

<snip>
I thought Leigh's post was proving the last line would be read even if it
didn't end in newline.
I didn't realise it was to prove about failbit either.
 
M

Marco


Thanks for the explanations about the bits.
while ( getline( fileIn, line ) || fileIn.gcount() != 0 ) {
if ( !fileIn ) {
// incomplete last line...
}
// ...
}

I don't see the need to write this. I always get the last line.
// incomplete last line...
never gets executed. If I understand you correctly this line should be
executed for instance if I read in a file that just contains »hello«. The
getline fails because eof is seen. But getline sees the »hello« with my
construct without gcount().
You didn't. Obviously, opinions as to when to use exceptions
vary, but in fact, my response was very oriented to you, the
context of your posting, and you're apparent programming level
in C++; Ian probably summed it up best with his response to me:
you don't use exceptions for a missing file unless the fact that
it is missing is somehow exceptional. (Which of course begs the
point as to what is exceptional, but in a short program which
reads a more or less random file, the fact that the file isn't
there could hardly be considered exceptional.)

I understand.
I'd write something like:

std::ifstream fileIn( name );
if ( !fileIn.open() )
throw ...

As I wrote before: if(!fileIn.open()) does not work, since open() has a void
return type and it cannot be converted to a bool. I can write

fileIn.open("file");
if (!fileIn) ... // This works
The choice of -1 probably isn't optimal here. The only value
guaranteed to be treated as an error is EXIT_FAILURE;

Thans for pointing this out.
It's fine; my comments above are really nits (except maybe for
the case where the file doesn't end with a new line---if you're
on Windows, try entering "abc", and nothing else, in Notepad,
then save it and use it to test your program).

I don't use windows, I used another editor. But I was not able to trigger the
problem you addressed. Maybe I did something wrong. Just writing »Hello« to a
file shouldn't result in a new line character, should it?
Another improvement that you'd want to make in production code:
before returning 0:
cout.flush();
if ( !cout )
// Write error in the output...
This is more important than closing the input (here, since the
input will be automatically closed when fileIn goes out of
scope).

I read everywhere that this is not necessary, indeed but one should do it
nonetheless. I put it, so it's clear when the file is closed.
If for some reason (e.g. disk full) there has been
a write error, the output data will not be complete, and your
user should definitely be informed.

cout.flush() writes everything what is left in the buffer to the screen (or to
a file when the output is redirected) if I'm not mistaken. But what does !cout
mean, that cout fails? But how can I inform the user if I cannot do a cout?
When should cout fail? cout writes to the screen, not to the disk.


Regards
Marco
 
I

Ian Collins

My original assertion included a code snippet with test data and results
which should have made it obvious I was referring to failbit behaviour
(look at the bloody while statement).

A clearer example would have been

#include <iostream>
#include <fstream>

int main()
{
std::ifstream f("y");
std::string s;
getline(f, s);
getline(f, s);
std::cout << f.fail() << ' ' << f.eof() << std::endl;
}

Which removes the third call to getline.
 
J

James Kanze

On 08/02/2011 15:37, James Kanze wrote:
If VC++ and g++ are behaving correctly then what you are asserting is
plain false. Given the following program:
int main()
{
std::ifstream f("c:\\tmp\\test.dat");
std::string s;
while(getline(f, s))
std::cout << "[" << s << "]\n";
}
The output is
[one]
[two]
Given the input file test.dat which contains:
(VC++, Windows)
00000000 6f 6e 65 0d 0a 74 77 6f |one..two|
(g++, Linux)
00000000 6f 6e 65 0a 74 77 6f |one.two|

In which case, I'm clearly mixing it up with something else.
(I'm not too sure how VC++ maps the input under Windows, but
I am sure that g++ under Linux treats a single 0a as a line
ending, and not a line separator.)

Checking in the standard: my description applies to some of the
other unformatted input functions, but not to getline. So the
correct loop for getline would be:

while ( getline( fileIn, line ) ) {
if ( fileIn.eof() ) {
// incomplete last line...
}
// ...
}

My bad. Sorry for the confusion.
 
J

James Kanze


Thanks for the explanations about the bits.
while ( getline( fileIn, line ) || fileIn.gcount() != 0 ) {
if ( !fileIn ) {
// incomplete last line...
}
// ...
}
I don't see the need to write this. I always get the last line.
// incomplete last line...
never gets executed. If I understand you correctly this line should be
executed for instance if I read in a file that just contains »hello«. The
getline fails because eof is seen. But getline sees the »hello« with my
construct without gcount().

That was my mistake. I was thinking of some other unformatted
read functions. This is one of the rare cases where it might
make sense to test for eof after a successful read, e.g.:

while ( getline( fileIn, line ) ) {
if ( fileIn.eof() ) {
// incomplete last line...
}
// ...
}

[...]
As I wrote before: if(!fileIn.open()) does not work, since
open() has a void return type and it cannot be converted to
a bool. I can write

Sorry. That's a typo. By passing the filename to the
constructor, open has already been called, and the test should
use is_open():

if ( !fileIn.is_open() ) ...
fileIn.open("file");
if (!fileIn) ... // This works

Also. In this particular case, I prefer the is_open, since it's
more explicit with regards to what I'm testing, but behind the
scenes:
if ( !fileIn.open() )
if ( fileIn.fail() )
if ( !fileIn )
all do exactly the same thing. (Immediately after an attempt to
open a file, at any rate. Before an attempt to open a file, the
last to will show success, although there is no file open, and
after other operations on an already open file, the last two
could show failure, although the file is open.)

[...]
I don't use windows, I used another editor. But I was not able
to trigger the problem you addressed. Maybe I did something
wrong. Just writing »Hello« to a file shouldn't result in
a new line character, should it?

I was wrong, see above. But with regards to just writing
"hello" to a file, it all depends. Unix is very line oriented
in its text handling, and the editor I normally use (vim, both
in Windows and in Unix) is incapable of writing a file without
a final newline.
I read everywhere that this is not necessary, indeed but one
should do it nonetheless. I put it, so it's clear when the
file is closed.

For input, it's not too critical.
cout.flush() writes everything what is left in the buffer to
the screen (or to a file when the output is redirected) if I'm
not mistaken.

That's a good first approximation.
But what does !cout mean,

if ( !cout )
is just the opposite of
if ( cout )
Streams are designed to convert implicitly and support operators
so that they can be used more or less as boolean values, at
least in if's and such. If the result of the conversion is
considered true, all preceding io has succeeded. If the result
is false, an "error" has occured.
that cout fails?

That depends on the system. The most frequent case is when the
output is going to disk, and the disk if full.
But
how can I inform the user if I cannot do a cout?

That's what cerr is for. And the final return status. Under
Unix, one common idiom is:
prog input > tmp && mv tmp input
prog (your program) reads input, and writes the transformed data
to a temporary file. If prog succeeds (returns 0 or
EXIT_SUCCESS), you then replace your original file with the
output. But only if prog succeeds; you don't want to replace
the original file if you've lost half of it, because the disk
was full.
When should cout fail?

Disk full is probably the most frequent case. Or a loss of
connection to the machine on which you were working. Or
whatever. cout can go pretty much anywhere, and there are all
sorts of possible failures.
cout writes to the screen, not to the disk.

Cout writes to where ever the OS wants it to. And the OS's
I use allow you to choose between the screen, a file, a pipe to
another process, and a few other odds and ends. If you're
writing to the screen, when working on a remote machine, and
loose the connection, it's generally not important. If you're
writing to a pipe, and the reader disappears, no problem either.
But if you're writing to disk... See above.
 
M

Marco


Thanks for the explanations about the bits.
while ( getline( fileIn, line ) || fileIn.gcount() != 0 ) {
if ( !fileIn ) {
// incomplete last line...
}
// ...
}
I don't see the need to write this. I always get the last line.
// incomplete last line...
never gets executed. If I understand you correctly this line should be
executed for instance if I read in a file that just contains »hello«. The
getline fails because eof is seen. But getline sees the »hello« with my
construct without gcount().

That was my mistake.

No problem.
Sorry. That's a typo.
if ( !fileIn.is_open() ) ...

That works.
Also. In this particular case, I prefer the is_open, since it's more
explicit with regards to what I'm testing, but behind the scenes:
if ( !fileIn.open() )
if ( fileIn.fail() )
if ( !fileIn )
all do exactly the same thing.

Same typo again? Nevermind.
I was wrong, see above.

No problem.

But with regards to just writing "hello" to a file, it all depends. Unix
is very line oriented in its text handling, and the editor I normally use
(vim, both in Windows and in Unix) is incapable of writing a file without a
final newline.

I use vim, too. That vim isn't capable of writing text files without final
newline makes me think of the reason. In general vim isn't wrong. Maybe a text
file has to have a final newline by definition. But that's just a guess, I
don't know.
That depends on the system. The most frequent case is when the
output is going to disk, and the disk if full.

That's what I also thought of in the first place, output redirection.
That's what cerr is for.
Right.

And the final return status.

True. I completely forgot about this, my fault.
Cout writes to where ever the OS wants it to. And the OS's
I use allow you to choose between the screen, a file, a pipe to
another process, and a few other odds and ends. If you're
writing to the screen, when working on a remote machine, and
loose the connection, it's generally not important. If you're
writing to a pipe, and the reader disappears, no problem either.
But if you're writing to disk... See above.

Of course, I just thought about the default case.


Regards
Marco
 
B

Bo Persson

James said:
Marco wrote:
[...]
I mean to switch the exceptions off again after having switched
them on before to avoid that the while loop is able to throw an
exception?
But here the open() functions is not likely to throw any
exceptions of the kind you try to catch. Open() returns NULL if it
cannot open the file (which is not considered exceptional).

The open function also sets failbit if it fails to open the
file, and he's explicitly asked for an exception if failbit is
set.

Yes, I was confusing it with basic_filebuf::eek:pen, which returns a
pointer.

Still, it seems a bit excessive to enable exceptions just to catch the
one possibly thrown from fstream::eek:pen, instead of just calling
is_open to see if the open attempt was succesful.



Bo Persson
 
J

James Kanze

James said:
Marco wrote:
[...]
I mean to switch the exceptions off again after having switched
them on before to avoid that the while loop is able to throw an
exception?
But here the open() functions is not likely to throw any
exceptions of the kind you try to catch. Open() returns NULL if it
cannot open the file (which is not considered exceptional).
The open function also sets failbit if it fails to open the
file, and he's explicitly asked for an exception if failbit is
set.
Yes, I was confusing it with basic_filebuf::eek:pen, which returns a
pointer.
Still, it seems a bit excessive to enable exceptions just to catch the
one possibly thrown from fstream::eek:pen, instead of just calling
is_open to see if the open attempt was succesful.

Agreed. If you want an exception, just write:
if ( !file.is_open() )
throw ...
after the open.

Part of the problem is that the granularity in the error types
is not fine enough. failbit can mean too many different things
for you to want to convert them all to exceptions. Depending on
the situation, you might want to throw if you can't open a file,
or if there is a format error in the file, but you almost never
want an exception to indicate that you've finished reading the
file.
 

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,755
Messages
2,569,534
Members
45,008
Latest member
Rahul737

Latest Threads

Top