There is the following code, from here
class Base {
int i;
public:
class BaseExcept {};
Base(int i) : i(i) { throw BaseExcept(); }
};
class Derived : public Base {
public:
class DerivedExcept {
const char* msg;
public:
DerivedExcept(const char* msg) : msg(msg) {}
const char* what() const { return msg; }
};
Derived(int j) try : Base(j) {
// Constructor body
cout << "This won't print" << endl;
}
catch (BaseExcept&) {
throw DerivedExcept("Base subobject threw");;
}
};
int main() {
try {
Derived d(3);
}
catch (Derived::DerivedExcept& d) {
cout << d.what() << endl; // "Base subobject threw"
}
}
My question is, why the thrown exception is not caught here
catch (BaseExcept&) {
throw DerivedExcept("Base subobject threw");;
}
But the catch in main?
catch (Derived::DerivedExcept& d) {
cout << d.what() << endl; // "Base subobject threw"
}
Why does it output "Base subobject threw"
According to my understanding, the thrown exception should be caught in the catch after try (or the function body equivalent to try), but there is no, why?
What is the propagation path of the exception?
code from there
My question is this, try catch I have seen before all have this form.
try{}
catch(){}
So I think for the following snippet
Derived(int j) try: Base(j) {
// Constructor body
cout << "This won't print" << endl;
}
catch (BaseExcept&) {
throw DerivedExcept("Base subobject threw");;
}
When Derived() throws an exception, it should be caught by the catch (BaseExcept&)in the following line, not by the catch (Derived::DerivedExcept& d) in the main function.
But when I comment out it here
catch (Derived::DerivedExcept& d) {
//cout << d.what() << endl; // "Base subobject threw"
}
There will be no "Base subobject threw" output.
This is different from what I expected. I am learning basic exception knowledge. Did I understand something wrong
Derived(int j) try : Base(j) {
// Constructor body
cout << "This won't print" << endl;
}
catch (BaseExcept&) { // why the thrown exception is not caught here
throw DerivedExcept("Base subobject threw");;
}
The only way for the program to output Base subobject threw is if the exception is actually caught where you do not think it's caught. The string does not exist anywhere else in the program.
But the catch in main?
That's because you throw an exception in the catch. That exception is not caught by the same catch (which would result in infinite recursion in this case). It's caught by the outer try..catch which you have in main.
Related
I understand that exception handler catch(...) in C++ handles any type of exception. I am wondering what happens if it has to handle an exception that is of some class type - is the object of that class passed to this handler by reference or by value?
This is the code that could help in understanding this. When the exception of type B is thrown in "Inner try", an unnamed temporary object of class B is created with the default constructor of class B. When I run this program, copy constructor of class B doesn't get called at all, and this unnamed temporary object of class B is destroyed only after executing "Outer try 3", which means that object was propagated backwards all the way to the "Outer try 3". So my guess is that objects are passed by reference to the catch(...) handler, but I wanted to see if this is correct reasoning.
#include <iostream>
using namespace std;
class A {
public:
A() {
cout << "Default constructor of class A" << endl;
}
A(const A& a) {
cout << "Copy constructor of class A" << endl;
}
A(A&& a) noexcept {
cout << "Move constructor of class A" << endl;
}
~A() {
cout << "Destructor of class A" << endl;
}
};
class B {
public:
B() {
cout << "Default constructor of class B" << endl;
}
B(const B& b) {
cout << "Copy constructor of class B" << endl;
}
B(B&& b) noexcept {
cout << "Move constructor of class B" << endl;
}
~B() {
cout << "Destructor of class B" << endl;
}
};
int main() {
try {
try {
try {
try {
throw A();
}
catch (A a) {
cout << "Inner try" << endl;
throw B();
}
}
catch (...) {
cout << "Outer try 1" << endl;
throw;
}
}
catch (...) {
cout << "Outer try 2" << endl;
throw;
}
}
catch (...) {
cout << "Outer try 3" << endl;
}
}
When you throw an exception, the exception object is created from the operand to throw. It is an object stored in an unspecified way.
When a matching handler for the exception is reached and the handler is not ..., then the handler's parameter is initialized from the exception object.
Essentially, if you declare a catch parameter as a non-reference type, you are getting a copy of the exception object (or of a base class subobject) in the handler. This is what you see in the A handler and why there is a call to the copy constructor. The copy lives until the handler exits. If you declare the parameter a reference type, then you will get a reference to the exception object and it will always refer to the same object if you rethrow the exception.
Rethrowing with throw; does not actually do anything with the parameter of the catch clause. It simply causes the exception handling to continue searching the catch clauses and stack unwinding. The exception object is still the same.
Nothing about this changes if the handler is catch(...). There is no variable (reference or not) to initialize in the handler, but throw; will rethrow and continue the search for a handler with the same exception object.
When a handler exits without rethrowing the exception, then the exception object is destroyed. This happens at the end of your outer-most catch for the B exception object and at the end of the inner-most catch for the A exception object. (You get two destructor calls to A, one for the catch parameter and one for the exception object.)
Here's a curious one. I have a class A. It has an item of class B, which I want to initialize in the constructor of A using an initializer list, like so:
class A {
public:
A(const B& b): mB(b) { };
private:
B mB;
};
Is there a way to catch exceptions that might be thrown by mB's copy-constructor while still using the initializer list method? Or would I have to initialize mB within the constructor's braces in order to have a try/catch?
Have a read of http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)
Edit: After more digging, these are called "Function try blocks".
I confess I didn't know this either until I went looking. You learn something every day! I don't know if this is an indictment of how little I get to use C++ these days, my lack of C++ knowledge, or the often Byzantine features that litter the language. Ah well - I still like it :)
To ensure people don't have to jump to another site, the syntax of a function try block for constructors turns out to be:
C::C()
try : init1(), ..., initn()
{
// Constructor
}
catch(...)
{
// Handle exception
}
It's not particularly pretty:
A::A(const B& b) try : mB(b)
{
// constructor stuff
}
catch (/* exception type */)
{
// handle the exception
}
I know it has been awhile since this discussion started. But that try-and-catch construct mentioned by Adam is part of the C++ standard and is supported by Microsoft VC++ and GNU C++.
Here is the program that works. By the way the the catch generates automatically another exception to signal about the constructor failure.
#include <iostream>
#include <exception>
#include <string>
using namespace std;
class my_exception: public exception
{
string message;
public:
my_exception(const char* message1)
{
message = message1;
}
virtual const char* what() const throw()
{
cout << message << endl;
return message.c_str();
}
virtual ~my_exception() throw() {};
};
class E
{
public:
E(const char* message) { throw my_exception(message);}
};
class A
{
E p;
public:
A()
try :p("E failure")
{
cout << "A constructor" << endl;
}
catch (const exception& ex)
{
cout << "Inside A. Constructor failure: " << ex.what() << endl;
}
};
int main()
{
try
{
A z;
}
catch (const exception& ex)
{
cout << "In main. Constructor failure: " << ex.what() << endl;
}
return 0;
}
You could work with lazy initialization, though, that is hold a unique_ptr to Reader in MyClass and create it with new. That way, you do not even need the flag has_reader but you can just see if your unique_ptr is initial or not.
#include <iostream>
#include <memory>
using namespace std;
class MyOtherClass
{
public:
MyOtherClass()
{
throw std::runtime_error("not working");
}
};
class MyClass
{
public:
typedef std::unique_ptr<MyOtherClass> MyOtherClassPtr;
MyClass()
{
try
{
other = std::make_unique<MyOtherClass>();
}
catch(...)
{
cout << "initialization failed." << endl;
}
cout << "other is initialized: " << (other ? "yes" : "no");
}
private:
std::unique_ptr<MyOtherClass> other;
};
int main()
{
MyClass c;
return 0;
}
Of course, there are also solutions without using exceptions at all but I assumed that this is a prerequisite in your setting.
I don't see how you'd do that with initializer-list syntax, but I'm also a bit sceptical that you'll be able to do anything useful by catching the exception in your constructor. It depends on the design of the classes, obviously, but in what case are you going to fail to create "mB", and still have a useful "A" object?
You might as well let the exception percolate up, and handle it wherever the constructor for A is being called.
I have a problem with the following code. As we can see I have already handled the exception thrown by A's constructor in C's constructor, why should I bother to catch and handle the exception again in the main function?
#include <iostream>
class WException : public std::exception
{
public:
WException( const char* info ) : std::exception(info){}
};
class A
{
public:
A( int a ) : a(a)
{
std::cout << "A's constructor run." << std::endl;
throw WException("A constructor throw exception.");
}
private:
int a;
};
class B
{
public:
B( int b ) : b(b)
{
std::cout << "B's constructor body run." << std::endl;
throw WException("B constructor throw exception");
}
private:
int b;
};
class C : public A, public B
{
public:
C( int a, int b ) try : A(a), B(b)
{
std::cout << "C's constructor run." << std::endl;
}
catch( const WException& e )
{
std::cerr << "In C's constructor" << e.what() << std::endl;
}
};
int main( int argc, char* argv[] )
{
try
{
C c( 10, 100 );
}
catch( const WException& e )
{
std::cerr << "In the main: " << e.what() << std::endl;
}
return 0;
}
You cannot actually catch an exception in a constructor. You can handle it, but you have to rethrow it or another exception. The reason is about object integrity and object lifetimes:
If the construction of a throws, a part of c has not been initialized and is completely missing - lifetime of a never starts. a is not an optional part of C, otherwise it had to be a pointer or a std::optional (since C++14 - boost::optional before that).
So how do you assemble a C if one of its vital parts cannot be constructed? You can't. c can never start to exist as a complete object, so there is no way you can exit the constructor normally. That's the reason why if construction of a member object fails, construction of the whole object has to fail, i.e. has to throw an exception.
If you don't throw an exception in C::C's catch block, the compiler will do so for you.
C++ Standard, §15.3,15:
The currently handled exception is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor.
For a broader treatment on that topic, see http://www.gotw.ca/gotw/066.htm
Basically I want to simulate .NET Exception.InnerException in C++. I want to catch exception from bottom layer and wrap it with another exception and throw again to upper layer. The problem here is I don't know how to wrap the catched exception inside another exception.
struct base_exception : public std::exception
{
std::exception& InnerException;
base_exception() : InnerException(???) { } // <---- what to initialize with
base_exception(std::exception& innerException) : InnerException(innerException) { }
};
struct func1_exception : public base_exception
{
const char* what() const throw()
{
return "func1 exception";
}
};
struct func2_exception : public base_exception
{
const char* what() const throw()
{
return "func2 exception";
}
};
void func2()
{
throw func2_exception();
}
void func1()
{
try
{
func2();
}
catch(std::exception& e)
{
throw func2_exception(e); // <--- is this correct? will the temporary object will be alive?
}
}
int main(void)
{
try
{
func1();
}
catch(base_exception& e)
{
std::cout << "Got exception" << std::endl;
std::cout << e.what();
std::cout << "InnerException" << std::endl;
std::cout << e.InnerException.what(); // <---- how to make sure it has inner exception ?
}
}
In the above code listing I am not sure how to initialize the "InnerException" member when there is no inner exception. Also I am not sure whether the temporary object that is thrown from func1 will survive even after func2 throw?
Since C++ 11 you have new options:
You can use std::exception_ptr.
The exception is then preserve until last exception_ptr to this
exception is destroyed.
struct base_exception : public std::exception
{
std::exception_ptr InnerException;
base_exception() {}
base_exception(std::exception& innerException)
: InnerException(std::make_exception_ptr(innerException))
{}
};
Or you can simply use std::nested_exception.
You should also take a look at boost exception for an alternative solution to wrapping.
Also I am not sure whether the
temporary object that is thrown from
func1 will survive even after func2
throw?
No. Unless you rethrow the exception with throw;. You could implement this if you'd allow only some (limited) set of exception types.
//inversion of the problem :)
struct base_exception : public std::exception
{
std::list<base_exception*> snowball;
base_exception() { }
void add(base_exception* e) { snowball.push_back(e); }
};
void func2()
{
func2_exception e;
e.add(new func2_exception());
throw e;
}
void func1()
{
try
{
func2();
}
catch(base_exception& e)
{
e.add(new func1_exception());
throw e;
}
}
int main(void)
{
try
{
func1();
}
catch(base_exception& e)
{
std::cout << "Got exception" << std::endl;
//print info in the direct order of exceptions occurence
foreach(base_exception* exception, e.snowball)
{
std::cout << exception->what();
std::cout << "next exception was:" << std::endl;
}
}
}
hmmmm...
One problem with the inner exception is the possibility to throw it again while maintaining polymorphic behaviour.
This can be (somewhat) alleviate by actually managing the exception lifetime yourself and providing polymorphic copies.
// Base class
class exception: virtual public std::exception, private boost::noncopyable
{
public:
virtual exception* clone() const = 0;
virtual void rethrow() const = 0; // throw most Derived copy
};
// ExceptionPointer
class ExceptionPointer: virtual public std::exception
{
public:
typedef std::unique_ptr<exception> pointer;
ExceptionPointer(): mPointer() {}
ExceptionPointer(exception* p): mPointer(p) {}
ExceptionPointer(pointer p): mPointer(p) {}
exception* get() const { return mPointer.get(); }
void throwInner() const { if (mPointer.get()) mPointer->rethrow(); }
virtual char* what() const { return mPointer.get() ? mPointer->what() : 0; }
private:
pointer mPointer;
};
How to use ?
try
{
// some code
}
catch(exception& e)
{
throw ExceptionPointer(e.clone());
}
// later on
try
{
}
catch(ExceptionPointer& e)
{
e.throwInner();
}
As stated by others, boost::exception is a nice option. However, like all options that use a common base class approach, they rely on all thrown exceptions being derived from that base class. If your intermediary catch handlers need to add information to an exception from a third party library it won't work.
An option that might be sufficient is to have intermediary catch handlers like this:
catch (std::exception& ex)
{
std::string msg = ex.what();
msg.append(" - my extra info");
ex = std::exception(msg.c_str()); // slicing assignment
throw; // re-throws 'ex', preserving it's original type
}
This only works for implementations of std::exception that provide a constructor taking a string parameter (e.g. VC++). The std::exception constructor taking a string is a non-standard extension.
Here's a curious one. I have a class A. It has an item of class B, which I want to initialize in the constructor of A using an initializer list, like so:
class A {
public:
A(const B& b): mB(b) { };
private:
B mB;
};
Is there a way to catch exceptions that might be thrown by mB's copy-constructor while still using the initializer list method? Or would I have to initialize mB within the constructor's braces in order to have a try/catch?
Have a read of http://weseetips.wordpress.com/tag/exception-from-constructor-initializer-list/)
Edit: After more digging, these are called "Function try blocks".
I confess I didn't know this either until I went looking. You learn something every day! I don't know if this is an indictment of how little I get to use C++ these days, my lack of C++ knowledge, or the often Byzantine features that litter the language. Ah well - I still like it :)
To ensure people don't have to jump to another site, the syntax of a function try block for constructors turns out to be:
C::C()
try : init1(), ..., initn()
{
// Constructor
}
catch(...)
{
// Handle exception
}
It's not particularly pretty:
A::A(const B& b) try : mB(b)
{
// constructor stuff
}
catch (/* exception type */)
{
// handle the exception
}
I know it has been awhile since this discussion started. But that try-and-catch construct mentioned by Adam is part of the C++ standard and is supported by Microsoft VC++ and GNU C++.
Here is the program that works. By the way the the catch generates automatically another exception to signal about the constructor failure.
#include <iostream>
#include <exception>
#include <string>
using namespace std;
class my_exception: public exception
{
string message;
public:
my_exception(const char* message1)
{
message = message1;
}
virtual const char* what() const throw()
{
cout << message << endl;
return message.c_str();
}
virtual ~my_exception() throw() {};
};
class E
{
public:
E(const char* message) { throw my_exception(message);}
};
class A
{
E p;
public:
A()
try :p("E failure")
{
cout << "A constructor" << endl;
}
catch (const exception& ex)
{
cout << "Inside A. Constructor failure: " << ex.what() << endl;
}
};
int main()
{
try
{
A z;
}
catch (const exception& ex)
{
cout << "In main. Constructor failure: " << ex.what() << endl;
}
return 0;
}
You could work with lazy initialization, though, that is hold a unique_ptr to Reader in MyClass and create it with new. That way, you do not even need the flag has_reader but you can just see if your unique_ptr is initial or not.
#include <iostream>
#include <memory>
using namespace std;
class MyOtherClass
{
public:
MyOtherClass()
{
throw std::runtime_error("not working");
}
};
class MyClass
{
public:
typedef std::unique_ptr<MyOtherClass> MyOtherClassPtr;
MyClass()
{
try
{
other = std::make_unique<MyOtherClass>();
}
catch(...)
{
cout << "initialization failed." << endl;
}
cout << "other is initialized: " << (other ? "yes" : "no");
}
private:
std::unique_ptr<MyOtherClass> other;
};
int main()
{
MyClass c;
return 0;
}
Of course, there are also solutions without using exceptions at all but I assumed that this is a prerequisite in your setting.
I don't see how you'd do that with initializer-list syntax, but I'm also a bit sceptical that you'll be able to do anything useful by catching the exception in your constructor. It depends on the design of the classes, obviously, but in what case are you going to fail to create "mB", and still have a useful "A" object?
You might as well let the exception percolate up, and handle it wherever the constructor for A is being called.