Unhandled Exception Question

I

Immortal Nephi

I looked at vector’s header. I only see that there is only throw in
some functions, but they don’t have try / catch block.
If try / catch block is not written, then throw will be executed to
the operating system directly to trigger unhandled exception.
Correct?
If you want to use exception handler, you will include exception’s
header.

For example

#include <exception>

try {
vector< int > v;
v.push_back( 1 );
v.push_back( 2 );
v.push_back( 3 );

v.at( 4 ) = 5;
}
catch ( exception &e ) {
cerr << “Error: “ << e.what() << endl;
}

Is my example above correct? It triggers an exception handler to
report that subscript is out of range.
Without try / catch block, unhandled exception is always triggered
when at() throws subscript out of range.
 
M

Michael Doubez

        I looked at vector’s header.  I only see that there is only throw in
some functions, but they don’t have try / catch block.
        If try / catch block is not written, then throw will be executed to
the operating system directly to trigger unhandled exception.
Correct?

Not exactly.
If no handler is found, std::terminate() is called.

It the exception if thrown from a object's constructor/destructor
whith static storage duration, the exceptions are not caught.
        If you want to use exception handler, you will include exception’s
header.

Not necessarily. You can also catch all exceptions:
catch(...){
// all exceptions
}
For example

#include <exception>

try {
        vector< int > v;
        v.push_back( 1 );
        v.push_back( 2 );
        v.push_back( 3 );

        v.at( 4 ) = 5;}

catch ( exception &e ) {
        cerr << “Error: “ << e.what() << endl;

}

        Is my example above correct?

Apart from the missing 'main' enclosing the code, missing #include
 It triggers an exception handler to
report that subscript is out of range.

It triggers an exception and search for a matching exception handler.
Upon entering the exception handler, the stack is unwound.
        Without try / catch block, unhandled exception is always triggered
when at() throws subscript out of range.

It triggers an exception and search for a matching exception handler
and doesn't find any. You would also have an unhandled exception with
the following code:
try {
vector< int > v;
// ...
v.at( 4 ) = 5;
}
catch ( int e ) {
cerr << “Error: “ << e << endl;
}

It is implementation defined whether stack is unwound when calling
std::terminate().

By the way, there is no unhandled exception mechanism to trigger.
AFAIK the message you have is part of the implementation of your
compiler and is not mentioned in the standard.
 
I

Immortal Nephi

Not exactly.
If no handler is found, std::terminate() is called.

It the exception if thrown from a object's constructor/destructor
whith static storage duration, the exceptions are not caught.

Let me understand clearly.

void foo( int index ) {
if ( index < 0 || index > 15 )
throw;
}

This function does not have try / catch block. If throw is executed,
then terminate() function is called. Correct?
Maybe you suggest to put terminate() function inside foo() function
to replace throw. You can write your own terminate() function and
uses set_terminate().
Not necessarily. You can also catch all exceptions:
catch(...){
  // all exceptions





}






Apart from the missing 'main' enclosing the code, missing #include


It triggers an exception and search for a matching exception handler.
Upon entering the exception handler, the stack is unwound.
Please clarify what you mean stack is unwind? If exception handler
in the C++ Compiler’s setting is turned off, how do exception handler
work?
 
R

red floyd

Let me understand clearly.

void foo( int index ) {
if ( index< 0 || index> 15 )
throw;
}

This function does not have try / catch block. If throw is executed,
then terminate() function is called. Correct?
Maybe you suggest to put terminate() function inside foo() function
to replace throw. You can write your own terminate() function and
uses set_terminate().

No. As written, it calls terminate(), but only if foo() is not called
by an exception handler.

What you are thinking of is:

#include <stdexcept>

void foo(int index)
{
if (index < 0 || index > 15)
throw std::runtime_error("bad index");
}

In this case, what happens if someone in the call stack that eventually
invoked foo() has an exception handler for std::runtime_exception, then
that handler will be invoked. For example, in the code below, even
though there's no handler in foo(), terminate() is not called, because
the call stack has a handler for runtime_error.

// definition of foo as above.
#include <iostream>
#include <ostream>

void g()
{
foo(27);
}

void f()
{
g();
}

void h()
{
try
{
f();
}
catch(std::runtime_error& e)
{
std::cout << "Runtime error "
<< e.what()
<< std::endl;
}
}

int main()
{
h();
}
 
B

Bart van Ingen Schenau

        Let me understand clearly.

void foo( int index ) {
        if ( index < 0 || index > 15 )
                throw;

}

        This function does not have try / catch block.  If throw is executed,
then terminate() function is called.  Correct?

Maybe. That completely depends on the context in which the function is
called.
If this function is called, with a parameter outside the range
[0..15], in the context of a catch handler, then the exception that
was being handled gets re-thrown. If the function is called with that
parameter in some other context, then the throw; statement results in
a call to std::terminate.
        Please clarify what you mean stack is unwind?

Stack unwinding means that all objects with automatic storage duration
(aka non-static local variables), whose scope and lifetime has been
ended due to the exception, are destructed.
In layman's terms, as the exception flies from the throw to the catch
statement further up the stack, the stack-frames for the functions
that are returned from are cleaned up.
 If exception handler
in the C++ Compiler’s setting is turned off, how do exception handler
work?

If the compiler setting has turned exception-handling off, then it is
no longer a C++ compiler, so there is no way to tell what it will do
if you try to throw an exception.

Bart v Ingen Schenau
 
M

Michael Doubez

[snip - answered elsethread]
        Please clarify what you mean stack is unwind?  If exception handler
in the C++ Compiler’s setting is turned off, how do exception handler
work?

When the exception is thrown, the code looks for a exception handler:
i.e. a try block it is executed from with a catch close taking as
parameter a type matching the type of the exception thrown.

If none is found meaning no try block or no matching handler up to the
execution entry point (main() or static initialisation) then
std::terminate is called. The objects with automatic lifetime are not
necessarily destroyed upon entering std::terminate(), this is
implementation defined.

If one handler is found. The objects with automatic duration (i.e.
living on the stack) will be destroyed (kind of pop out of the stack
sequentially) up to the beginning of the try block that have a
matching handler. Then the execution jumps to the code of the catch
clause with a matching parameter (the handler).

As an example:
#include <iostream>
#include <cassert>

struct Automatic
{
Automatic(std::string const & name):m_name(name)
{ std::cout<<"Constructor of "<<m_name<<std::endl;}
~Automatic()
{ std::cout<<"Destructor of "<<m_name<<std::endl;}

std::string m_name;
};

Automatic staticObject("'Static Object'");

void foo()
{
Automatic inFoo("'Object in foo'");
throw "string exception";
Automatic neverHere("'Object never constructed'");
}

int main(int argc)
{
Automatic beforeTry("'Object before try'");

// caught exception
try {
Automatic inTry("'Object in try'");
foo(); // throws char const *
Automatic afterFoo("'Nothing executes after foo'");
}
catch(int a)
{
assert( false && "parameter does not match" );
}
catch( char const * str)
{
Automatic inCatch("'Object in catch'");
}

if( argc == 2 )
{ // uncaught exception
try {
Automatic inUncaught("'Object before uncaught'");
throw "uncaught exception";
}
catch(int a)
{
assert( false && "parameter does not match" );
}
}
}

Calling the program without uncaught exception you will notice that
'Object in try' is destroyed before entering catch().

# ./test
Constructor of 'Static Object'
Constructor of 'Object before try'
Constructor of 'Object in try'
Constructor of 'Object in foo'
Destructor of 'Object in foo'
Destructor of 'Object in try'
Constructor of 'Object in catch'
Destructor of 'Object in catch'
Destructor of 'Object before try'
Destructor of 'Static Object'

Calling the program with uncaught exception, you will notice that
'Object before uncaught', 'Object before try' (and 'Static Object' for
that matter) never get destroyed on my compiler with my compilation
options.

# ./test z
Constructor of 'Static Object'
Constructor of 'Object before try'
Constructor of 'Object in try'
Constructor of 'Object in foo'
Destructor of 'Object in foo'
Destructor of 'Object in try'
Constructor of 'Object in catch'
Destructor of 'Object in catch'
Constructor of 'Object before uncaught'
terminate called after throwing an instance of 'char const*'
Aborted (core dumped)

[snip]
 
G

Goran

If exception handler
in the C++ Compiler’s setting is turned off, how do exception handler
work?

I would guess that this situation would fall under "undefined
behavior". If you turn off exception handling, exception handlers are
simply not there. How do you expect them to "work"? If you do turn
exception off, but still to throw, your program will crash.

You can turn exception handling of for any part of your code, that's
fine. But then __you__ have to make sure that any function you call in
that part can't (or at least, won't) throw.

Goran.
 
J

James Kanze

I would guess that this situation would fall under "undefined
behavior".

More likely the "we're not talking about C++" category. If you
turn off support for exceptions, the language isn't C++, and
you'll have to depend on the vendor's documentation of what the
language is.
 
G

Goran

More likely the "we're not talking about C++" category.  If you
turn off support for exceptions, the language isn't C++, and
you'll have to depend on the vendor's documentation of what the
language is.

The problem is elimination of exception handling from generated code.
In practice, it's not hard to know that a particular zone is a no-
throw one. If performance is critical, it might be desirable to shed
any overhead in places, including "I swear, it will be unused"
exception handling.

But in practice, compiler can't know whether some part is a no-throw,
for various reasons. It would have been nice if it could, but...

Therefore, I see no problem in implementations allowing such "no-
throw" zones in code.

That said, I am 100% with you on a related notion there's no C++
without exceptions. :)

Goran.
 
J

Joshua Maurice

The problem is elimination of exception handling from generated code.
In practice, it's not hard to know that a particular zone is a no-
throw one. If performance is critical, it might be desirable to shed
any overhead in places, including "I swear, it will be unused"
exception handling.

But in practice, compiler can't know whether some part is a no-throw,
for various reasons. It would have been nice if it could, but...

Therefore, I see no problem in implementations allowing such "no-
throw" zones in code.

That said, I am 100% with you on a related notion there's no C++
without exceptions. :)

A necessary but sad state of affairs, I agree.

Ideally, this would be mostly unnecessary because exception handling
would basically carry zero runtime overhead for the not-thrown
execution path. The good and intended implementation of exceptions is
the out-of-line table approach. With that, there is no extra
instructions which must be executed in a function with a throw
statement or try block. There is overhead in terms of a larger
executable, but with virtual memory, this carries no additional memory
requirements (though perhaps a larger swap size). Also, if the
compiler and linker put the exceptions tables into a different virtual
page in the executable or shared lib, then this carries basically no
runtime speed cost at all.

Without virtual memory and sufficient swap size, then yes I agree it
could be a problem, in which case it would be very useful for a
compiler to optimize away exception table entries for regions of code
which cannot throw. However, if this is a concern, if there isn't
virtual memory, then I would hazard a guess that you've already turned
off exception support or are using C.

Moreover, I think C++ has really suffered as a language because of
this. Sadly, half the major implementers of C++ missed the memo on
what exceptions were meant to be, and they implemented them in such a
way that a try block or the presence of a throw exception incurs
runtime speed costs even on the no-exception-thrown execution paths.
Because of this, those rabidly concerned with speed do not use
exceptions in performance critical code, and once you lose exceptions,
you lose a major part of C++.

First, exceptions are a very useful way to signal rare and unlikely
fatal-ish errors. Second, without exceptions, constructors cannot
signal failure, so a large portion of objects must have a zombie
state, there must be a separate init function which does the work of
construction. Either way, it's much more tedious. Example:
foo f(some args); //might throw std::bad_alloc
f.a(); //might throw std::bad_alloc
f.b(); //might throw std::bad_alloc
f.c(); //might throw std::bad_alloc
return f;
vs the common:
foo f;
if (COMPANY_PREFIX_SUCCESS != f.init(some args))
return COMPANY_PREFIX_FAILURE;
if (COMPANY_PREFIX_SUCCESS != f.a())
return COMPANY_PREFIX_FAILURE;
if (COMPANY_PREFIX_SUCCESS != f.b())
return COMPANY_PREFIX_FAILURE;
if (COMPANY_PREFIX_SUCCESS != f.c())
return COMPANY_PREFIX_FAILURE;
return f;
vs the common way to make this more bearable with macros:
foo f;
COMPANY_PREFIX_HANDLE_FAILURE(f.init(some args));
COMPANY_PREFIX_HANDLE_FAILURE(f.a());
COMPANY_PREFIX_HANDLE_FAILURE(f.b());
COMPANY_PREFIX_HANDLE_FAILURE(f.c());
return f;

Without exceptions, we're left with a very C way of doing things.
Every nontrivial function must have its return value be an error code.
It's more boileplate code, so it's tedious on the programmer, it's
more error prone for the programmer, it takes longer for the
programmer to write, and it takes longer for another programmer to
read, so it's worse for maintenance as well.

Finally, proper use of exceptions on a proper implementation results
in faster code than the C way of error return codes. Each error return
code requires a branch, which at worst stalls the pipeline, and at
best takes up a spot in the instruction pipeline, instruction cache,
and other such things. On the no-throw execution path, the (usually
very) common path, code using exceptions does not have this extra
usually-useless instruction in-line, which means it's slightly
faster.

PS: I've posted this three times now. Let's see if it finally takes it
this time.
 

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,871
Messages
2,569,919
Members
46,172
Latest member
JamisonPat

Latest Threads

Top