Andrey Rubliov
Andrey Rubliov

Reputation: 1597

Why throwing exception which is a reference calls copy constructor?

Why throwing exception which is a reference calls copy constructor?

struct Error
{
    Error() {}
    Error(const Error&) = delete;
};

int main()
{
    Error& error = *new Error;

    throw error;
}

Compilation error:

error: declared here
     Error(const Error&) = delete;

It does not happen when throwing pointer like:

int main()
{
    Error* error = new Error;

    throw error;
}

This is OK.

Upvotes: 0

Views: 262

Answers (2)

Arthur Golubev 1985
Arthur Golubev 1985

Reputation: 677

Before unwinding stack a throw operator (except throw; without an argument, used for rethrowing) creates an exception object (in a special memory area). Depending on circumstances, the object is initialized in different ways: constructor, copy constructor, move constructor (https://en.cppreference.com/w/cpp/language/copy_elision) using what was provided to the throw operator. Providing the reference is ok, but three:

  • if you provide a reference in an arguments list, it depends on receiving party, what is actually received, a reference or a value copy;
  • compiler needs to initialize an exception object, because what was provide to the throw operator will not live when the exception handling catch block is running (the stack will have been unwound then; in case of the pointer, the pointer provided, though the object it points to in your case is alive, and in the catch block you have a copy of the pointer to the same object);
  • it is not possible to initialize a reference in runtime; so, in your case, the compiler expects the copy constructor in order to initialize an exception object using the reference you provided (copy constructors usually takes values to initialize the object using references to the initial one).

When you pass a reference to Error to the throw operator, the type of the exception object is Error, and we need to initialize an Error exception object in that specific memory area..

When you pass a pointer to Error to a throw operator, the type of the exception object is a pointer to Error (Error *), so the pointer is copied, not the Error object which the pointer points to. The copying pointer to error has nothing to do with calling the copy constructor of Error, so you don’t have the error in that case.

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385098

You cannot throw a reference. Throwing always copies the thrown expression value into a special area of storage set aside for thrown objects. Otherwise, you'd almost always be "catching" a dangling reference, as is [theoretically] the case in your code.

Your Error type cannot be copied, so the program is impossible.

However, a pointer can of course be copied, and the main problem in your final example is a memory leak. Also your program will simply terminate at the throw statement as you don't have any try/catch.

Upvotes: 6

Related Questions