4
try
{
    range_error r("Hi I am hereeeee!");
    cout << r.what() << endl;   // print "Hi I am hereeeee!"  // case one
    exception *p2 = &r; 
    cout << p2->what() << endl; // print "Hi I am hereeeee!"  // case two
    throw p2;
}
catch (exception *e)
{
    cout << e->what() << endl;  // print "Unknown exception"  // case three
}

Question>

I don't know why case three prints "Unknown exception" instead of "Hi I am hereeeee!"? The printed result is copied from VS2010

q0987
  • 34,938
  • 69
  • 242
  • 387

3 Answers3

5

This program results in undefined behavior. Because the variable r is declared inside the try block, it goes out of scope before the catch handler is invoked. At this point, e points to some area on the stack where an object of type range_error used to exist.

The following program should print the expected results:

range_error r("Hi I am hereeeee!");
try
{
    cout << r.what() << endl;   // print "Hi I am hereeeee!"  // case one
    exception *p2 = &r; 
    cout << p2->what() << endl; // print "Hi I am hereeeee!"  // case two
    throw p2;
}
catch (exception *e)
{
    cout << e->what() << endl;  // print "Hi I am hereeeee!"  // case three
}

However, you should not throw a pointer to an object, you should throw the object itself. The run-time library will store a copy of the range_error object and pass that copy to the exception handler.

Thus, you should use the following code instead:

try
{
    range_error r("Hi I am hereeeee!");
    cout << r.what() << endl;   // print "Hi I am hereeeee!"  // case one
    throw r;
}
catch (const exception& e)
{
    cout << e.what() << endl;  // print "Hi I am hereeeee!"  // case two
}
André Caron
  • 44,541
  • 12
  • 67
  • 125
  • I should haven identified this problem myself. Thank you – q0987 Aug 10 '11 at 21:32
  • Jeez, you **must** have copied me, except your answer is better. – john Aug 10 '11 at 21:32
  • @John: Except, I also posted first, and fixed the comment in the `catch` block ;-) – André Caron Aug 10 '11 at 21:35
  • Apart from throwing by value, the generally used approach is to [catch by reference](http://stackoverflow.com/questions/2023032/catch-exception-by-pointer-in-c/2023045#2023045). The code in the answer is already like that, but I think it deserves an explicit remark. – noe Aug 10 '11 at 23:24
  • @ncases: indeed. However, the OP's been asking several questions about exception handling and seems well aware of [slicing](http://stackoverflow.com/questions/7014626/c-throw-dereferenced-pointer) objects in exception handlers. – André Caron Aug 10 '11 at 23:31
3

Because by the time you get to the catch, your range_error has been destroyed and you're catching a dangling pointer. Either move the range_error declaration outside the try block or, better yet, throw an instance and catch by reference.

Fred Larson
  • 60,987
  • 18
  • 112
  • 174
1

Because the pointed to exception object has gone out of scope by the time you catch the exception. If you wrote

range_error r("Hi I am hereeeee!");
try
{
    cout << r.what() << endl;   // print "Hi I am hereeeee!"  // case one
    exception *p2 = &r; 
    cout << p2->what() << endl; // print "Hi I am hereeeee!"  // case two
    throw p2;
}
catch (exception *e)
{
    cout << e->what() << endl;  // print "Unknown exception"  // case three
}

it would print what you expected.

john
  • 85,011
  • 4
  • 57
  • 81