Gaurav K
Gaurav K

Reputation: 2975

Exception and Copy Constructor : C++

Referring to http://en.wikipedia.org/wiki/Copy_elision

I run below code:

#include <iostream>

struct C {
  C() {}
  C(const C&) { std::cout << "Hello World!\n"; }
};

void f() {
  C c;
  throw c; // copying the named object c into the exception object.
}          // It is unclear whether this copy may be elided.

int main() {
  try {
    f();
  }
  catch(C c) {  // copying the exception object into the temporary in the exception declaration.
  }             // It is also unclear whether this copy may be elided.
}

The Output I got:

Gaurav@Gaurav-PC /cygdrive/d/Trial
$ make clean
rm -f Trial.exe Trial.o

Gaurav@Gaurav-PC /cygdrive/d/Trial
$ make
g++ -Wall Trial.cpp -o Trial

Gaurav@Gaurav-PC /cygdrive/d/Trial
$ ./Trial
Hello World!
Hello World!

I understand that the compiler might have optimized the code with unnecessary copying, which it is not doing here.

But What I want to ask, How does two calls to the copy constructor is being made?

catch(C c) - Since we are passing by value, hence here the copy constructor is being called.

But at throw c how is copy constructor being called? Can someone explain?

Upvotes: 11

Views: 6315

Answers (3)

uvdn7
uvdn7

Reputation: 93

But at throw c how is copy constructor being called? Can someone explain?

C++ exceptions must be copy/move constructable if you want to do throw ex; as what's happening behind the scene is that the C++ ABI will allocate an exception object (via __cxa_allocate_exception) somewhere and copy/move your exception object, either it's on the heap or stack, before it actually starts the stack unwinding process.

Reference https://blog.the-pans.com/cpp-exception-2/

Upvotes: 0

Vishal Chovatiya
Vishal Chovatiya

Reputation: 99

Copy & Move constructor while throwing user-defined type object

struct demo
{
    demo() = default;
    demo(demo &&) = delete;
    demo(const demo &) = delete;
};

int main()
{
    throw demo{};
    return 0;
}
  • Upon throw expression, a copy of the exception object always needs to be created as the original object goes out of the scope during the stack unwinding process.
  • During that initialization, we may expect copy elision (see this) – omits copy or move constructors (object constructed directly into the storage of the target object).
  • But even though copy elision may or may not be applied you should provide proper copy constructor and/or move constructor which is what C++ standard mandates(see 15.1). See below compilation error for reference.
error: call to deleted constructor of 'demo'
    throw demo{};
          ^~~~~~
note: 'demo' has been explicitly marked deleted here
    demo(demo &&) = delete;
    ^
1 error generated.
compiler exit status 1
  • If we catch an exception by value, we may also expect copy elision(compilers are permitted to do so, but it is not mandatory). The exception object is an lvalue argument when initializing catch clause parameters.

From: 7 best practices for exception handling in C++

Upvotes: 0

Alok Save
Alok Save

Reputation: 206526

throw c;     

Creates a temporary object and it is this temporary object that is thrown. The creation of the temporary might be through copy/move constructor. And yes this copy/move can be elided.


References:
C++11 15.1 Throwing an exception

§3:

A throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type.........

§5:

When the thrown object is a class object, the copy/move constructor and the destructor shall be accessible, even if the copy/move operation is elided (12.8).

Upvotes: 14

Related Questions