Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: Throwing an exception invokes the copy constructor?

We have an custom error class that is used whenever we throw an exception:

class AFX_CLASS_EXPORT CCLAError : public CObject

It has the following copy constructor defined:

CCLAError(const CCLAError& src) { AssignCopy(&src); } // (AssignCopy is a custom function)

It was originally written and compiled / linked with MSVC6 (Visual Studio 2003). I am in the process of doing necessary changes to get it to compile and link against MSVC8+ (VS 2008+)

When the msvc8 linker is invoked, i get the following error:

LNK2001: unresolved external symbol "private: __thiscall CObject::CObject(class CObject const &)" (??0CObject@@AAE@ABV0@@Z)

I understand what the error is telling me: no copy constructor is defined for some child of CObject, so its going all the way up the inheritance tree until it hits CObject, which as no copy constructor defined.

I first saw the error when compiling the library that defines and first throws a CCLAError, which is why I am proceeding as if that is the cause.

I was able to resolve the error by changing

throw CCLAError( ... )

to

throw new CCLAError( ... )

and

catch(CCLAError& e)
{
   throw e;
}

to

catch(CCLAError& e)
{
   throw;
}

However, I do not understand why re-throwing a caught exception would invoke the copy constructor. Am I missing somethnig completely obvious? Subsequently, why would removing the variable holding a reference to a caught exception cause the copy constructor to not be invoked?

like image 638
johnluetke Avatar asked Oct 16 '25 17:10

johnluetke


2 Answers

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.

like image 121
James McNellis Avatar answered Oct 18 '25 07:10

James McNellis


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.

like image 30
K-ballo Avatar answered Oct 18 '25 07:10

K-ballo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!