There are some other considerations related to using exceptions effectively.
The C++ standard effectively disallows having two active exceptions at one time. If an exception is thrown while control is being passed back up the call stack because of an existing exception, the program is required to terminate(). In practice, the only ways in which an exception can be generated while another is active is from an objects destructor. This means that throwing an exception from a destructor is something to avoid. In other words, destructors should provide a "nothrow" guarantee. The C++ standard library also strongly discourages the practice of throwing exceptions in destructors, but for different reasons: recovering from exceptions in destructors of an arbitrary user-supplied type is quite difficult to implement and carries a significant run time cost. An example of this is
class MyException{};
class Foo
{
public:
~Foo() {throw MyException();};
};
void Func()
{
Foo x;
throw MyException();
}
int main()
{
try
{
Func(); // this will result in program termination
}
catch (...)
{
// we will never get here
}
return 0;
}
The basic mechanism by which exceptions are propagated to callers is compiler dependent. However, the C++ standard allows invoking of the exception's copy constructor in that process. This means it is necessary to ensure that copying of exception types cannot throw exceptions (the result may be a call to abort()).
It is also not a good idea to define exception types so that constructing them is able to throw an exception. If this is done, an exception may occur in the process of constructing an exception, and the caller might be thrown a different exception from that intended. A side effect of this is that it is not a good idea to use dynamic memory allocation when creating an exception type. This means it is a poor idea to use types like std::string as members of an exception type. For example;
#include
struct MyException
{
std::string type; // BAD: construction of this may throw
};
void Func()
{
MyException e; // either line in this function may throw
e.type = "Hello";
throw e;
}