Catching exceptions

M

magnus.moraberg

Hi,

I have the following incomplete code -

File file;
file.open(filePath);

try
{
someOneElsesApi::startComplexProcessingOfFile(file);
std::cout << "The file is now processed" << std::endl;
}
catch exception(/* all exceptions */)
{
std::cout << "The file didn't process because: " << std::endl;
}

startComplexProcessingOfFile() can throw a whole range of different
exceptions.

How do I catch them and inform the user in a useful manner. In python,
there is a base exception class which can be used for this purpose. C#
has inner exceptions which I also found quite useful.

Thanks for your help,
 
V

Vladimir Jovic

Hi,

I have the following incomplete code -

File file;
file.open(filePath);

try
{
someOneElsesApi::startComplexProcessingOfFile(file);
std::cout << "The file is now processed" << std::endl;
}
catch exception(/* all exceptions */)
{
std::cout << "The file didn't process because: " << std::endl;
}

startComplexProcessingOfFile() can throw a whole range of different
exceptions.

How do I catch them and inform the user in a useful manner. In python,
there is a base exception class which can be used for this purpose. C#
has inner exceptions which I also found quite useful.

You can use:
catch(...)
but it will catch all exceptions, and you will not know which one is caught.

It is better to create all catch cases, and act accordingly. After all,
you should know which exceptions are thrown, and what can be done for each.

Something like:

try
{
f(); // throws an exception
}
catch ( const exception1 &e )
{
// do 1
}
catch ( const exception2 &e )
{
// do 2
}
catch ( ... )
{
// ?
}
 
A

Alf P. Steinbach

* (e-mail address removed):
I have the following incomplete code -

File file;
file.open(filePath);

try
{
someOneElsesApi::startComplexProcessingOfFile(file);
std::cout << "The file is now processed" << std::endl;
}
catch exception(/* all exceptions */)
{
std::cout << "The file didn't process because: " << std::endl;
}

startComplexProcessingOfFile() can throw a whole range of different
exceptions.

How do I catch them and inform the user in a useful manner. In python,
there is a base exception class which can be used for this purpose. C#
has inner exceptions which I also found quite useful.

If the exceptions are all derived from some base class T (e.g. std::exception),
just do

try
{
// Whatever.
}
catch( std::exception const& x )
{
std::cerr << "!" << x.what() << std::endl;
}

If the exceptions are of unrelated types then you can do

try
{
// Whatever.
}
catch( ... )
{
std::cerr << "!" << exceptionText() << std::endl;
}

where exceptionText is a routine that you have defined tailored to the exception
types you expect, e.g. like

std::string exceptionText()
{
try
{
throw;
}
catch( A const& a )
{
return exceptionTextFrom( a );
}
catch( B const& b )
{
return exceptionTextFrom( b )
}
catch( C const& c )
{
return exceptionTextFrom( c );
}
catch( std::exception const& x )
{
return x.what();
}
catch( ... )
{
return "Uknown exception";
}
}

where exceptionTextFrom might be a routine that you define, or just direct code
to access the exception object's message.

For anything but the smallest program it is however generally a bad idea to
present the message carried by an exception to the user as a main message. It's
probably not adapted to the context it appears in. It's probably about internal
technical details that the user doesn't care about and doesn't have access to.
It's probably expressed in a technical terminology/jargon that the user doesn't
understand. It may even be in a national language that user doesn't understand.
Exception information is generally for programmers (e.g. log it).

Cheers & hth,

- Alf
 
J

Jorgen Grahn

Hi,

I have the following incomplete code -

File file;
file.open(filePath);

try
{
someOneElsesApi::startComplexProcessingOfFile(file);
std::cout << "The file is now processed" << std::endl;

Do you use std::endl here because you explicitly want flushing of cout
at this point, or because you mistakenly think \n is not portable?
}
catch exception(/* all exceptions */)
{
std::cout << "The file didn't process because: " << std::endl;
}

startComplexProcessingOfFile() can throw a whole range of different
exceptions.

How do I catch them and inform the user in a useful manner. In python,
there is a base exception class which can be used for this purpose.

Not really. As far as I know, Python is like C++; you can throw any
object. And even if there *was* such an Exception class, you would
want to catch IOError in this case, to be able to tell the user
something meaningful like "failed because 'foo.txt' is read
protected".

Returning to C++ ... if someOneElsesApi::startComplexProcessingOfFile()
can throw "a whole range of different exceptions" and you have to care
about more than two or three of them, I'd argue that it is broken.

/Jorgen
 
J

James Kanze

On Mon, 11 May 2009 01:52:15 -0700 (PDT),
Do you use std::endl here because you explicitly want flushing
of cout at this point, or because you mistakenly think \n is
not portable?

Or most likely, because it is the standard way of terminating a
line. (Standard in the sense of "usual or default practice".)
At least from what he's posted, there's no reason to assume that
the flush is causing a performance problem, so there's no reason
to not use std::endl.
 
A

Alf P. Steinbach

* James Kanze:
Or most likely, because it is the standard way of terminating a
line. (Standard in the sense of "usual or default practice".)
At least from what he's posted, there's no reason to assume that
the flush is causing a performance problem, so there's no reason
to not use std::endl.

It's also debatable whether

#include <iostream>
int main() { std::cout << "Bah\n"; }

is guaranteed to produce any output at all.

I don't know (though I suspect answer is "no") and don't care, but anyone
recommending not using endl and criticizing others for using it should know and
be able to back it up with some quote from the standard.


Cheers,

- Alf
 
J

Jerry Coffin

[email protected] says... said:
It's also debatable whether

#include <iostream>
int main() { std::cout << "Bah\n"; }

is guaranteed to produce any output at all.

I don't know (though I suspect answer is "no") and don't care, but anyone
recommending not using endl and criticizing others for using it should know and
be able to back it up with some quote from the standard.

I don't see how there's any room for debate at all. See [lib.ios::Init]
(27.4.2.1.6). std::ios_base::Init is a class that (acts like it) keeps a
reference count to ensure that cin, cout, cerr, and clog (and wide
variants) are created once in a program that uses them, and flushed
before the program exits.
 
A

Alf P. Steinbach

* Jerry Coffin:
[email protected] says... said:
It's also debatable whether

#include <iostream>
int main() { std::cout << "Bah\n"; }

is guaranteed to produce any output at all.

I don't know (though I suspect answer is "no") and don't care, but anyone
recommending not using endl and criticizing others for using it should know and
be able to back it up with some quote from the standard.

I don't see how there's any room for debate at all. See [lib.ios::Init]
(27.4.2.1.6). std::ios_base::Init is a class that (acts like it) keeps a
reference count to ensure that cin, cout, cerr, and clog (and wide
variants) are created once in a program that uses them, and flushed
before the program exits.

Of course, you can provide a quote or reference to the place the standard
guarantees the creation of at least one such object?

And, what about e.g. an ofstream?


Cheers & hth.,

- Alf
 
J

Jerry Coffin

[email protected] says... said:
Of course, you can provide a quote or reference to the place the standard
guarantees the creation of at least one such object?

Sort of, in 27.3/2. That's what actually creates cin, cout, etc. -- so
without it, the problem isn't going to be lack of output from the
program -- it's going to be extra output from the linker saying your
program has undefined externals, and then you'll get no executable at
all.
And, what about e.g. an ofstream?

What about it? Do you mean: "Is all output that has been written to an
fstream required to be written to the external file?" If so, the answer
is basically yes. ~std::basic_filebuf() calls close() (§27.8.1.2/3).
Close flushes the output by calling overflow(EOF) if a put area exists
(§27.8.1.3/6). Of course, this assumes normal exit -- if the program
exits via abort() (for one example) buffers aren't flushed.
 
J

James Kanze

* James Kanze:
It's also debatable whether
#include <iostream>
int main() { std::cout << "Bah\n"; }
is guaranteed to produce any output at all.

Since when? The standard guarantees that flush will be called
on all of the standard stream objects during a clean shutdown.
(There may be problems if you output to std::cout in the
destructor of a static object. The stream is guaranteed not to
be destructed, but you might have to manually ensure the flush
to ensure that data is actually output.)

Of course, one of my major arguments for using std::endl instead
of '\n', by default, is that, like it or not, not all shutdowns
are clean. And debugging is a lot easier if the output is
actually indicative of how far the program has gotten.
I don't know (though I suspect answer is "no") and don't care,
but anyone recommending not using endl and criticizing others
for using it should know and be able to back it up with some
quote from the standard.

It's more an engineering issue than a standards one. Basically,
std::endl is the "standard" way of terminating a line (standard
in the sense of "usual" or "accepted practice", not in the sense
of ISO/IEC 14882); replacing it with '\n' is an optimization.
Which shouldn't be undertaken prematurely.
 
A

Alf P. Steinbach

* Jerry Coffin:
Sort of, in 27.3/2.

Thanks, I think that's the sought for guarantee as far as the in-practice is
concerned, because it clearly demonstrates the intent.

That's what actually creates cin, cout, etc. -- so
without it, the problem isn't going to be lack of output from the
program -- it's going to be extra output from the linker saying your
program has undefined externals, and then you'll get no executable at
all.

Sorry, no. There is an implication that placement new is used, since cout is a
reference, so whether or not an Init object is ever created won't affect the
things the linker sees. The question was more like whether the standard
somewhere requires the use of the Init mechanism, and it seems 27.3/2 is it.

What about it? Do you mean: "Is all output that has been written to an
fstream required to be written to the external file?" If so, the answer
is basically yes. ~std::basic_filebuf() calls close() (§27.8.1.2/3).
Close flushes the output by calling overflow(EOF) if a put area exists
(§27.8.1.3/6). Of course, this assumes normal exit -- if the program
exits via abort() (for one example) buffers aren't flushed.

Thanks again. In summary, the relevant references are 27.3/2, 27.8.1.2/3 and
27.8.1.3/6. And although the formal is a bit lacking, as a matter of practice it
seems there's no danger from "\n" (instead of endl) for a normal execution.


Cheers,

- Alf
 
A

Alf P. Steinbach

* James Kanze:
Since when?

That would be late 1998. :)

Before the standardization it was even worse.

E.g. Scott Meyers discovered that the actual workings and guarantees about
buffering, endl etc., in the draft standard, were so vague and counter intuitive
that he had to omit an item about preferentially using "\n" in Effective C++.

The standard guarantees that flush will be called
on all of the standard stream objects during a clean shutdown.
(There may be problems if you output to std::cout in the
destructor of a static object. The stream is guaranteed not to
be destructed, but you might have to manually ensure the flush
to ensure that data is actually output.)

I've yet to see that formal guarantee demonstrated.

It seems that it's in the class of "the standard guarantees that <iostream> is
enough to use cout, << etc." (oops, we forgot to actually state that!), which
you helped to have fixed in C++0x.

However, else-thread Jerry refers to 27.3/2, and as a matter of practicality to
me that is convincing enough about the standard's authors' *intention*, namely
that the standard is intended to require initialization of the standard iostream
objects via the basic_ios::Init mechanism, which in turn provides flushing
guarantees.

Of course, one of my major arguments for using std::endl instead
of '\n', by default, is that, like it or not, not all shutdowns
are clean. And debugging is a lot easier if the output is
actually indicative of how far the program has gotten.


It's more an engineering issue than a standards one. Basically,
std::endl is the "standard" way of terminating a line (standard
in the sense of "usual" or "accepted practice", not in the sense
of ISO/IEC 14882); replacing it with '\n' is an optimization.
Which shouldn't be undertaken prematurely.

I agree with this. :)


Cheers,

- Alf
 
J

Jerry Coffin

* Jerry Coffin:

Thanks, I think that's the sought for guarantee as far as the in-practice is
concerned, because it clearly demonstrates the intent.

Right -- AFAIK, there's nothing that says the implementation shall
create an object of type std::ios_base::Init.

[ ... ]
Thanks again. In summary, the relevant references are 27.3/2, 27.8.1.2/3 and
27.8.1.3/6. And although the formal is a bit lacking, as a matter of practice it
seems there's no danger from "\n" (instead of endl) for a normal execution.

Yes, I think that's a reasonable summary.
 
J

James Kanze

[ ... ]
Of course, you can provide a quote or reference to the place
the standard guarantees the creation of at least one such
object?
Sort of, in 27.3/2. That's what actually creates cin, cout,
etc. -- so without it, the problem isn't going to be lack of
output from the program -- it's going to be extra output from
the linker saying your program has undefined externals, and
then you'll get no executable at all.

That's what triggers the construction of cin, cout, etc. It's
not what defines the symbols.

For various reasons, an implementation must do some sort of
funny stuff with the standard stream objects: they can't be
simply variables at namespace scope, with the given type, unless
the implementation has some mechanism to ensure that they are
constructed before (or during) the construction of the first
ios_base::Init object, and that thy are the very last object to
be destructed. Thus, g++ declares them as raw memory
(char[ sizeof( ostream ) ], etc., using a compiler extension to
ensure alignment); ios_base::Init uses placement new to
construct them. (I suspect that this is probably the most
widespread solution.)

And if you try outputting before any ios_base::Init objects are
constructed, you really do get undefined behavior. According to
§27.3: "The objects are constructed and the associations are
established at some time prior to or during the first time an
object of class ios_base::Init is constructed, and in any case
before the body of main begins execution." But Alf is right
that there is no guarantee that any ios_base::Init objects are
ever constructed, and thus, that the streams will ever be
flushed. I'm sure this is a defect; I'll raise the issue in
comp.std.c++.

(In practice, all of the compilers I know ensure the
construction before main by simply defining an instance of
ios_base::Init somewhere in the library, where it will be
constructed before main. Also, for a variety of historical
reasons, all of the implementations I know define a static
What about it? Do you mean: "Is all output that has been
written to an fstream required to be written to the external
file?" If so, the answer is basically yes.
~std::basic_filebuf() calls close() (§27.8.1.2/3). Close
flushes the output by calling overflow(EOF) if a put area
exists (§27.8.1.3/6). Of course, this assumes normal exit --
if the program exits via abort() (for one example) buffers
aren't flushed.

Also, if you do something like:
std::eek:stream* p = new std::eek:fstream( "filename" ) ;
and never delete p, the buffers won't be flushed. Or if you do
something like:

int
main()
{
std::eek:fstream out( "filename" ) ;
// ...
exit( 0 ) ;
}

In general, however, I would consider it an error to output to a
file without explicitly closing it, then testing the error
status, and reporting a write error somehow. For command line
programs, the return status should be EXIT_FAILURE, or some
implementation specific value which represents failure, in such
cases, probably with an error message on cerr. For a GUI, I'd
expect some sort of pop-up error message. For a server,
whatever the server is supposed to do in case of a serious
error---under Unix, syslog, and maybe an email to someone.
 
J

James Kanze

* James Kanze:

[...]
I've yet to see that formal guarantee demonstrated.

On rereading, I think you're right. The formal guarantee is
only present if there is at least one instance of ios_base::Init
is destructed. I'm pretty sure that this is a defect, however.

In practice, every implementation I know defines a static
instance of ios_base::Init in <iostream>. So any program which
includes <iostream> will construct an instance of this object.
This was required by the ULS specification of <iostream.h>, but
It seems that it's in the class of "the standard guarantees
that <iostream> is enough to use cout, << etc." (oops, we
forgot to actually state that!), which you helped to have
fixed in C++0x.

(Actually, I don't think that it was the intent that <iostream>
suffice for using cout, etc. But since that's what all
implementations do, people have come to expect it.)

Yes. C++0x also guarantees that if <iostream> is included, the
standard objects will be constructed before any variables at
namespace scope which follow the include. The usual way of
achieving this is to declare a static instance of ios_base::Init
which would also guarantee the flush. But the said:
However, else-thread Jerry refers to 27.3/2, and as a matter
of practicality to me that is convincing enough about the
standard's authors' *intention*, namely that the standard is
intended to require initialization of the standard iostream
objects via the basic_ios::Init mechanism, which in turn
provides flushing guarantees.

I don't know what the actual intentions were, but I do know what
implementations do today, and what users expect. Practically
speaking, any implementation which doesn't do what is expected
will be considered wrong by the users, regardless of what it
can argue from the standard.

(My proposal concerning <iostream>, for example, wasn't based on
what the original intentions were, nor on what I thought they
should be, but on what implementations actually do and users
actually expect.)
 

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top