11

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?

Gaurav K
  • 2,864
  • 9
  • 39
  • 68

3 Answers3

14
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).

Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • Alok - Can You give me an example of move constructor ? Is it same as Move Assignment operator ? Can you please reply to `EDIT` part is the question for http://stackoverflow.com/questions/16418992/assignment-operator-for-an-object?noredirect=1#comment23544551_16418992 – Gaurav K May 08 '13 at 05:07
  • @BenVoigt, The comments seem more confident than the question, which is probably because they come straight from Wikipedia. – chris May 08 '13 at 05:07
  • There, the "initializes a temporary object" is what was missing. – Ben Voigt May 08 '13 at 05:12
  • @GauravK: C++11 introduces move semantics in addition to copy semantics already existing in C++03. [This](http://stackoverflow.com/questions/3106110/what-are-move-semantics) question might be a good place to start. – Alok Save May 08 '13 at 05:15
  • @AlokSave Is move constructor/move assignment operator defined by C++11 ? – Gaurav K May 08 '13 at 05:25
  • @AlokSave Also based on the answer I can conclude that a copy constructor is called in precisely four scenarios 1) Instantiating an object with another object i.e. `myClass Ob2 =Ob1` 2) Passing a Class Object by Value , to functions parameter 3) Returning a Class Object by Value 4) throwing an Class Object – Gaurav K May 08 '13 at 05:28
  • 1
    @GauravK: Yes introduced in C++11. And typically you shouldn't or cannot rely on counting copy/move constructor calls. A good compiler will apply copy elision through RVO or NRVo whenever it can. – Alok Save May 08 '13 at 05:36
0

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++

0

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/

uvdn7
  • 83
  • 4