Good day. Suppose there is a try-block, where a local object is passed by value (I know that this is bad)

#include <iostream> using namespace std; class CL { public: CL() { cout<<"CL()"<<endl; } CL(CL&) { cout<<"CL(CL&)"<<endl; } ~CL() { cout<<"~CL()"<<endl; } }; int main() { try { CL cl; throw cl; } catch (CL clcop) { cout<<"cl catched"<<endl; } } 

In what order should the copy constructor for clcop and the destructor for cl be called here? At first, as I understand it, the local cl is copied into a temporary throw'a object, but then different compilers have differences. VS2008 calls the copy constructor for clcop, and then the destructor for cl, devcpp calls the destructor first, and then copies it. How should it really be? PS did not throw through an explicit CL () call, since then, due to copy optimization, it does not occur

    1 answer 1

    I propose to modify the class a little

     class CL { public: CL() { cout<<"CL()" << this <<endl; } CL(CL&) { cout<<"CL(CL&)" << this <<endl; } ~CL() { cout<<"~CL()" << this <<endl; } }; 

    In this case, you can see who exactly they create and whom they remove. I compiled with g ++ (formally, this is the same mingw) and I got this conclusion:

     CL()0x7fff21efc32f CL(CL&)0x23bb090 ~CL()0x7fff21efc32f CL(CL&)0x7fff21efc32f cl catched ~CL()0x7fff21efc32f ~CL()0x23bb090 

    a strange thing is noticed that an object seems to be created and deleted with one address twice, but this is just a stack. And no more oddities - the object is created, copied. After that it is not needed and the compiler can insert its deletions. And maybe a little later. If I remember the standard correctly, then it should do this to the end of the function. The compiler could insert and remove the object later, but in this case he decided to reuse the stack nicely and put an object of the same type there.

    I think that if you do it for your code too, you will see that there is order in this chaos.

    • Why is the copy constructor not CL (const CL &)? - atwice
    • 2
      because it is also possible. Standard, clause 12.8.2. Moreover, there are still a couple of options available - volatile X& and const volatile X& . - KoVadim
    • The simple fact is that cl is not only a local variable of a function, but also a variable of a try block, i.e. it can be assumed that it should collapse on any exit from this block, including when calling throw. Only the decision when the object will be copied (before cl is destroyed or after) seems to be at the discretion of the compiler - ViktorKozlov
    • 2
      and how can you copy an object after its destruction? :) And so - the standard only determines to what point the object should be destroyed (in this case, before leaving the block). But the compiler can insert object destruction both at the end of the block, and right after the object is no longer needed. Just not all compilers can do such a complex analysis. I note that in the example that you have, the compiler can throw out the call to the destructor and insert the output into the console and the stack correction directly in place. - KoVadim
    • No) But only here a temporary object is copied, which turned out in throw, and the local object cl is destroyed (throw always creates a special temporary object that exists before the exception is processed, that is, two different objects), and the fact that the order of copying and destruction changes from compiler to compiler - ViktorKozlov