We have an custom error class that is used whenever we throw an exception:
class AFX_CLASS_EXPORT CCLAError : public CObject
It has the fol
The language specification allows the compilers to make as many copies of the original object as they want. There is no restriction on the number of copies.
That means, your custom exception class must have an accessible copy-constructor, either the compiler generated one, or user-defined one.
Several points:
1st of all don't call throw new foo()
use throw foo
2nd when your write:
catch(foo const &e) {
throw e;
}
You actually create a new exception, and if for example the exception that
was thrown is subclass of foo
they my calling throw e
you would loose this
information and actually use a copy constructor to generate foo
from e - whatever
it was.
Now when you call
catch(foo const &e) {
throw;
}
You don't create a new exception but rather propagate the same exception.
So: never use throw e;
to propagate the exception forward, use throw;
It appears that you have misunderstood what re-throw means. When you do -
catch(CCLAError& e)
{
throw e;
}
-- you are NOT rethrowing. Instead, as you have observed, you are indeed creating a copy of the new exception. Instead (again, as you have found for yourself), this is what is technically the correct way to re-throw:
catch(CCLAError& e)
{
throw;
}
Read chapter 14 in Stroustrup's TC++PL (14.3.1 deals with rethrowing).
Also, you do NOT have to do -
throw new CCLAError( ... )
Instead, do -
throw CCLAError( ... )
-- like you were doing before, only receive by CONST reference (you cannot hold a reference to a temporary).
catch(const CCLAError &e)
When you throw an exception, the object you're throwing generally resides on the stack. The stack is getting cleaned up as part of the process of throwing, so the compiler must make a copy that can continue to live beyond that point.
When you throw an object with new
, you're not throwing the actual object but you're throwing a pointer to the object. That means your catch
block must also catch a pointer rather than a reference. Don't forget to delete
the pointer or you'll have a memory leak!
When the catch block uses throw;
instead of throw e;
it can reuse the copy it made earlier and there's no need to make another copy.
The type of the object thrown must be copyable because the throw
expression may make a copy of its argument (the copy may be elided or in C++11 a move may take place instead, but the copy constructor must still be accessible and callable).
Rethrowing the exception using throw;
will not create any copies. Throwing the caught exception object using throw e;
will cause a copy of e
to be made. This is not the same as rethrowing the exception.
Your "updated" code does not work as you expect. catch (CCLAError&)
will not catch an exception of type CCLAError*
, which is the type of the exception thrown by throw new CCLAError(...);
. You would need to catch CCLAError*
. Do not do this, though. Throw exceptions by value and catch by reference. All exception types should be copyable.
However, I do not understand why re-throwing a caught exception would invoke the copy constructor.
It doesn't, but re-throwing the thrown exception is done with throw;
. When you do throw e;
you are requesting to throw a copy of the caught exception.