Temporary object not getting created when exception is caught by reference? - c++

class Error1
{
public:
int errorcode;
Error1(int x):errorcode(x){ cout<<"CTOR Error1"<<endl; }
//Error1(Error1& obj ){
// errorcode = obj.errorcode;
// cout<<"CopyCTOR Error1"<<endl;
//}
~Error1(){cout<<"DTOR Error1"<<endl; }
};
void fun()
{
cout<<"Inside fun"<<endl;
throw(Error1(5));
}
int main()
{
try{
fun();
}
catch(Error1& eobj)
{
cout<<"Error1 type occured with code:"<<eobj.errorcode<<endl;
}
cin.get();
}
OUTPUT:
Inside fun
CTOR Error1
DTOR Error1
Error1 type occured with code:5
DTOR Error1
This output indicates that a Error1 object is copy constructed for the catch handler. Since copy constructor is not defined for Error1 object default copy constructor is used.
When i uncomment the commented section for defining a copy constructor i get the the following output.
Inside fun
CTOR Error1
Error1 type occured with code:5
DTOR Error1
Why is it that only one DTOR is getting called? Even if exception is caught by reference i believe a temporary is still created.

What compiler are you using?
When you introduce (i.e. uncomment) your version of copy constructor with Error1& obj argument, the code is supposed to become invalid. throw is supposed to be able to create a copy of its argument, while your version of copy constructor disables copying of temporaries. The code is ill-formed. If your compiler accepts it, its is probably because it illegally allows binding non-const references to temporaries (I suspect it is MSVC++ compiler with extensions enabled).
The original experiment works as it is supposed/allowed to. The argument of throw is copied to an internal temporary which is later used to initialize catch parameters. Although the compilers are allowed to use your original temporary directly, extending its lifetime accordingly.

There may be other errors, but what I see right now is that throw(Error1(5)); creates a temporary (or rvalue) of type Error1. You want an lvalue, which means that you should either do throw(*new Error1(5)); (which I believe will create a memory leak, but I may be wrong), or you could create a global Error1 object and just throw that.
PS: I would be interested to know if throw(*new Error1(5)); does create a memory leak, if anyone would like to comment. Does catch destroy the object it catches? If so I think you should be fine with just creating new Error1s whenever you need them.

Related

Destruction of returned object

I was reading subsection 18.2 Constructors and Destructors of section 18 exception handling in C++17 standard draft where there is an example(page 384). I tried to understand where destruction of object A returned inside the try block happens but couldn't find. So I copied the example, added some prints and see that dtor of that object is never called. What am I missing here? Someone please explain what's happening here.
#include <stdio.h>
struct A {
int a_;
explicit A(int a):a_(a) {
printf("A(%d)'s ctor\n", a_);
}
~A() {
printf("A(%d)'s dtor\n", a_);
}
};
struct Y { ~Y() noexcept(false) {
printf("y's dtor\n");
throw 0; } };
A f() {
try {
A a(23);
Y y;
A b(56);
return A(100); // #1 who destructs this ??
} catch (...) {
printf("handling exception..\n");
}
printf("At line %d now..\n", __LINE__);
return A(200); // #2
}
int main() {
auto ret = f();
printf("f returned A(%d) object\n", ret.a_);
return 0;
}
Above code outputs following:
A(23)'s ctor
A(56)'s ctor
A(100)'s ctor
A(56)'s dtor
y's dtor
A(23)'s dtor
handling exception..
At line 34 now..
A(200)'s ctor
f returned A(200) object
A(200)'s dtor
...Program finished with exit code 0
According to the C++17 standard [except.ctor]/2:
If an exception is thrown during the destruction of temporaries or local variables for a return statement, the destructor for the returned object (if any) is also invoked. The objects are destroyed in the reverse order of the completion of their construction.
Then there is an illustrative example (which you modified slightly) to demonstrate: after the Y destructor throws, the next thing that happens is that the A(100) object should be destroyed, so you should see a destruction message.
The posted output indicates a compiler bug. This is very similar to the issue reported as LLVM bug 12286 and gcc bug 33799.
The latter is marked as being fixed in GCC 10 (after initially being reported in 2007!). However, testing with the version 10.0.1 20200418 (experimental) on Godbolt: even though the test case in the 33799 bug report is fixed, the code in this question remains unfixed. I added a comment to that bug report about this example.
Generally, the caller of a function is responsible for destroying the function's return value, but the precise details are part of the platform C++ ABI.
On most ABIs, calling a function that returns a non-trivial value (anything that doesn't safely fit in a register or perhaps two), is done by passing a hidden extra argument specifying where the return value should be constructed. The caller allocates space in it's frame for the return value and passes a pointer to that space.

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

Scope of Exception object when caught(using catch) by reference

I have 3 questions :
1. It is always said to catch the exception object by reference. In the following example i see that the destructor is called before the catch block executed, that means we are referring to an object in catch which must have gone out of scope by the time we use it. Why use reference then?
class MyException{
public:
~MyException() {
cout<<"Dtor for MyException called \n";
}
};
int main()
{
try{
MyException obj1;
throw obj1;
}
catch(MyException& obj)
{
cout<<"Catched unhandled exception";
}
}
2. Why is the destructor called twice here? Once before entering the catch block and second time after execution of catch completes.
3. The example in Lifetime of a thrown object caught by reference shows that the destructor is called just once i.e. after the catch block exits ONLY WHEN a copy constructor is defined in the class.
a. What is the role of copy constructor here when we are catching it by refrence?
b. Even after defining a copy constructor it never gets called anyways. So what impact does it make?
c. I tried to define a copy constructor in my example too as below but still i see destructor getting called twice.Why?:
MyException(const MyException& obj)
{
}
Can somebody answer all the 5 questions(3rd question has 3 parts).
You're throwing a copy of the exception you created as a local temporary. So there's two: the first is destroyed when you throw, the second (the copy) after the catch block is done.
Try this:
try { throw MyException{}; }
catch (MyException const& obj) { }
Edit: If your copy constructor is really not being called in your code then my guess is that the compiler has recognized that the exception class is empty? Compiler is free to perform any optimizations it chooses so long as the behavior of the code is as-if it hadn't. Exception to this is copy-ellision but if that was going on you'd not get the double destructor call.
throw ALWAYS makes a copy of an object you're throwing. You can't throw an object which is not copyable. If fact, throw can even fail if it can't allocate enough memory for a copy. This should explain why you see a destructor being called inside a try-block. It's a destructor of your local obj1. It goes out of scope as soon as your throw a copy of it.As for catching by reference, it is used to avoid unnecessary copying and, more importantly, potential slicing.
Once again, it was a destructor of your local obj1. It went after out scope when you threw a copy of it.
a) If you catch by reference, no copying is performed. Copying (with potential slicing) is performed ONLY if you catch by value.
b) You're wrong, throw calls a copy constructor to, well, make a copy of your object and throw it. The only case when a copy constructor won't be called is when you throw a temporary object and compiler elides a copy.
c) Refer to my first and second answer.
They recommend you take your catch block by reference to avoid slicing (since inheriting exceptions is standard) and to avoid needlessly copying, since throw copies unconditionally.
You cannot receive obj1 by reference as throw obj1 causes it to be destroyed (since it is no longer in scope). Due to this throw always copies to temporary memory location that you don't control.
obj1 and the temporary I mentioned before. obj is a reference to that temporary, the referenced temporary will be destroyed after the end of the catch block and before the next operation (similar to if it were actually local to the catch block).
A single destructor only happens when the copy is elided and the standard doesn't guarantee when that will happen, as copy elision is always optional. Defining a copy constructor makes no difference as the compiler defines it for you if you don't define it (and it can be created). Deleting the copy constructor would just result in throw being illegal.
a. As above, copy constructor to copy into the temporary. Reference to reference said temporary.
b. Did you actually delete the copy constructor? MyException(const MyException&) = delete; is how you delete a copy constructor, failing to define it just causes the compiler to make one for you. And to repeat, deleting it causes throw to be illegal.
c. Because the copy isn't elided and two objects exist, a temporary and your object.

Unexpected destructor call occurs when paired with move constuctor

The following code was compiled and run in Visual Studio 2012 Express for Windows Desktop, as a learning exercise.
#include <cstdio>
class X
{
public:
X() { printf("default constructed\n"); }
~X() { printf("destructed\n");}
X(const X&) { printf("copy constructed\n"); }
X(X&&) { printf("move constructed\n"); }
X & operator= (const X &) { printf("copy assignment operator\n"); }
};
X A() {
X x;
return x;
}
int main() {
{
A();
}
std::getchar();
}
When compiled with compiler optimizations disabled (/Od), the resulting output indicates that the destructor is called twice. This is a problem given that only one object is constructed. Why is the destructor being called twice? Wouldn't this be a problem if the class was managing it own resources?
default constructed
move constructed
destructed
destructed <<< Unexpected call
I tried a couple of experiments to try and explain the output, but ultimately these didn't lead to any useful explanations.
Experiment 1: When the same code is compiled with optimizations enabled (/O1 or /O2), the resulting output is:
default constructed
destructed
which indicates that the Named Return Value Optimization has elided the call to the move constructor, and masked the underlying problem.
Experiment 2: Disabled the optimization and commented out the move constructor. The output generated was what I expected.
default constructed
copy constructed
destructed
destructed
Keep in mind that when an object is the source of a move operation it will still be destroyed. So the source of the move needs to put itself in a state such that being destructed will not release resources that it no longer owns (since they were moved to another object). For example, any raw pointers (that will now be owned by the move constructed object) in the source object should be set to NULL.
The X in A is destroyed when it goes out of scope.
A returns a temporary object (constructed from X by the move constructor) which is a separate instance. This is destroyed in the caller's scope. That will cause the destructor to be called again (on the temporary).
The move constructor was picked because the compiler detected that X was going to be destroyed immediately afterward. To use this approach, the move constructor should nullify or reset any data in the original object so that the destructor will not invalidate any data that has been taken over by the destination of the move.
When you pass an rvalue by value, or return anything by value from a function, the compiler first gets the option to elide the copy. If the copy isn’t elided, but the type in question has a move constructor, the compiler is required to use the move constructor.
http://cpp-next.com/archive/2009/09/move-it-with-rvalue-references/
When you exit from the scope in which the temporary object was created, it is destroyed. If a reference is bound to a temporary object, the temporary object is destroyed when the reference passes out of scope unless it is destroyed earlier by a break in the flow of control.
http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr382.htm
The RVO can produce different behavior from the non-optimized version:
Return value optimization, or simply RVO, is a compiler optimization technique that involves eliminating the temporary object created to hold a function's return value.[1] In C++, it is particularly notable for being allowed to change the observable behaviour of the resulting program.[2]
http://en.wikipedia.org/wiki/Return_value_optimization
Although Michael's and jspcal answers are accurate, they didn't answer the heart of my question, which was why were there two destructor calls made. I was expecting just one.
The answer is that function A() returns a temporary object. Always. This is how function return values work, and move-semantics has no bearing on this fact. I guess Michael and jspcal assumed that I had not missed such a basic fact. I equated the term "moved" with the concept of "swap". When swapped, objects are not constructed and destructed. Hence I was expecting just one destructor call.
Since the returned object must be constructed and destructed, the second destructor call was made (and a second constructor call).
Now, the actual constructor selected to be executed depends on what is provided in the class definition. If a move-constructor is available, that will be called. Otherwise the copy constructor will be called.

Can objects with private copy constructors be thrown?

I've come across some exceptions issue that is unclear to me. In C++, when an object is thrown it is first copied to a temporary object, and the temporary object is then passed to the catching code. The copy involves the use of the object's class copy constructor. AFAIK, this means that if a class has a private copy constructor, it can't be used as an exception. However, in VS2010, the following code compiles and runs:
class Except
{
Except(const Except& other) { i = 2; }
public:
int i;
Except() : i(1) {}
};
int main()
{
try
{
Except ex1;
throw ex1; // private copy constructor is invoked
}
catch (Except& ex2)
{
assert(ex2.i == 2); // assert doesn't yell - ex2.i is indeed 2
}
return 0;
}
Is this legal?
It's not legal. Standard 15.1/5
If the use of the temporary object can be eliminated without changing
the meaning of the program except for the execution of constructors
and destructors associated with the use of the temporary object
(12.2), then the exception in the handler can be initialized directly
with the argument of the throw expression. When the thrown object is a
class object, and the copy constructor used to initialize the
temporary copy is not accessible, the program is ill-formed (even when
the temporary object could otherwise be eliminated). Similarly, if the
destructor for that object is not accessible, the program is
ill-formed (even when the temporary object could otherwise be
eliminated).
No, it's not.
15.1.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