Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If a thrown exception is always a copy of the exception object, why isn't this copy constructor being invoked?

Tags:

c++

Scott Meyers says:

C++ specifies that an object thrown as an exception is always copied and the copying is performed by the object's copy constructor.

But in my code:

struct test
{
    test() { cout << "constructor is called" << endl; }
    test(const test&) { cout << "copy constructor is called" << endl; }
    ~test() { cout << "destructor is called" << endl; }
};

void fun()
{
    throw test();
}

int main()
{
    try { 
       fun();
    }
    catch (test& t1) { cout << "exception handler" << endl; }
}

I do not see the exception object's copy constructor being called.

If I change the catch to receive the exception object by value then it is, but according to Meyers's quote the exception object should have been copied even when it's received by reference.

Why is the copy constructor is not called (even when exception handling is performed by reference)?

like image 701
Alok Avatar asked Jan 06 '12 16:01

Alok


People also ask

Can a copy constructor throw an exception?

Objects thrown as exceptions are always copied. But there may be cases where the default copy constructor doesn't work; specially when the class members are pointers. If we use such objects as exception objects we should make sure that our exception classes have proper copy constructors.

Can copy constructor throw an exception in C++?

However, the copy constructor for an exception object still must not throw an exception because compilers are not required to elide the copy constructor call in all situations, and common implementations of std::exception_ptr will call a copy constructor even if it can be elided from a throw expression.


1 Answers

Meyers is correct that a copy is made, semantically:

[C++11: 12.2/1]: Temporaries of class type are created in various contexts: binding a reference to a prvalue (8.5.3), returning a prvalue (6.6.3), a conversion that creates a prvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1), entering a handler (15.3), and in some initializations (8.5). [..]

[C++11: 15.1/4]: The memory for the temporary copy of the exception being thrown is allocated in an unspecified way, except as noted in 3.7.3.1. The temporary persists as long as there is a handler being executed for that exception.

However, copies can be elided by clever compilers and they are allowed to do so regardless of side-effects.

[C++11: 12.8/31]: When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization. This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

  • [..]
  • when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move.
  • [..]
like image 152
Lightness Races in Orbit Avatar answered Oct 01 '22 09:10

Lightness Races in Orbit