I have a variable which accumulates the current exception and needs to get cleaned when the current exception gets thrown (so that the same error does not get reported again). The problem is that throw std::move(ex); does not call the move constructor (which would clean ex), but rather calls a copy constructor (so that ex stays with the already thrown errors too). A MVCE follows:
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
class ThrowMoveTest : exception
{
public:
ThrowMoveTest(const string& what)
{
_what = what;
}
ThrowMoveTest(const ThrowMoveTest& fellow)
{
cout << "Copy " << what() << endl;
_what = fellow._what;
}
ThrowMoveTest(ThrowMoveTest&& fellow)
{
cout << "Move " << what() << endl;
_what = std::move(fellow._what);
}
virtual const char* what() const override
{
return _what.c_str();
}
private:
mutable string _what;
};
int main()
{
try
{
ThrowMoveTest tmt1("Test1");
throw move(tmt1);
}
catch (const ThrowMoveTest& ex)
{
cout << "Caught " << ex.what() << endl;
}
return 0;
}
I am using MSVC++2013 Update 5.
Is there something that I am doing wrong so that the move constructor does not get called for this reason? Is there away to throw an exception so that the temporary object used for exception storage in C++ gets move-constructed, rather than copy-constructed from the original?
What I try to avoid is double-copying: construction of a copy of tmt1, then cleaning the original, then using the copy in throw statement, which would construct another copy for temporary storage.
EDIT: The above code example gives the following output on MSVC++2013 Update 5
Copy
Caught Test1
While the expected output is
Move
Caught Test1
EDIT2: Submitted a compiler bug report https://connect.microsoft.com/VisualStudio/feedback/details/1829824
This is an MSVC bug. From [except.throw]:
Throwing an exception copy-initializes (8.5, 12.8) a temporary object, called the exception object.
That means we do:
ThrowMoveTest __exception_object = move(tmt1);
which should definitely call the move constructor.
Note that the move here is unnecessary and also damaging. [class.copy] stipulates that copy/move construction can be elided
— in a throw-expression (5.17), when the operand is the name of a non-volatile automatic object (other than
a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost
enclosing try-block (if there is one), the copy/move operation from the operand to the exception
object (15.1) can be omitted by constructing the automatic object directly into the exception object
So simply throw tmt1; would have allowed for tmt1 to be constructed directly into the exception object. Although neither gcc nor clang do this.
And even if the copy/move is not elided:
When the criteria for elision of a copy/move operation are met, but not for an exception-declaration, and the
object to be copied is designated by an lvalue [...] overload resolution
to select the constructor for the copy is first performed as if the object were designated by an rvalue.
So throw tmt1; would still move-construct the exception object.
This is a compiler bug. Standard ref §12.8/p32 states it should call the move constructor (acknowledge #Piotr Skotnicki).
Related
I'm testing how throwing when doing stack unwinding calls std::terminate by having the copy constructor of the class that is used to throw, throwing.
Per C++14 N4296 - §15.1.3:
Throwing an exception copy-initializes (8.5, 12.8) a temporary object,
called the exception object. The temporary is an lvalue and is used to
initialize the variable declared in the matching handler (15.3).
class X
{
public:
X() = default;
X(const X&)
{
throw std::runtime_error{"X copy constructor"};
}
};
int main()
{
try
{
throw X{};
}
catch(const std::exception& e)
{
std::cout << e.what() << std::endl; // this line gets executed, does not terminate
}
catch(const X& other)
{
std::cout << "X exception" << std::endl;
}
}
How come the above code doesn't call std::terminate? It is my understanding of the above code that the throw X{} inside the try, starts the stack winding and then the copy constructor gets called to call the handler, but the copy constructor throws as well. As a note if change the copy constructor's throw expression for throw X{} then it terminates.
Until the exception object has been initialized, no exception has been thrown yet. And thus, the system has not started doing exception handling.
Since the copy is throwing, and that's what initializes the exception object, the only throw that successfully executes is the one in the copy constructor.
As a note if change the copy constructor's throw expression for throw X{} then it terminates.
That's effectively a stack overflow due to infinite recursion. Each attempt to construct an exception object provokes another exception and another attempt to construct an exception object.
I'm trying to establish whether it is safe for a C++ function to return an object that has a constructor and a destructor. My understanding of the standard is that it ought to be possible, but my tests with simple examples show that it can be problematic. For example the following program:
#include <iostream>
using namespace std;
struct My
{ My() { cout << "My constructor " << endl; }
~My() { cout << "My destructor " << endl; }
};
My function() { My my; cout << "My function" << endl; return my; }
int main()
{ My my = function();
return 0;
}
gives the output:
My constructor
My function
My destructor
My destructor
when compiled on MSVC++, but when compiled with gcc gives the following output:
My constructor
My function
My destructor
Is this a case of "undefined behavior", or is one of the compilers not behaving in a standard way? If the latter, which ? The gcc output is closer to what I would have expected.
To date, I have been designing my classes on the assumption that for each constructor call there will be at most one destructor call, but this example seems to show that this assumption does not always hold, and can be compiler-dependent. Is there anything in the standard that specifies what should happen here, or is it better to avoid having functions return non-trivial objects ? Apologies if this question is a duplicate.
In both cases, the compiler generates a copy constructor for you, that has no output so you won't know if it is called: See this question.
In the first case the compiler generated copy constructor is used, which matches the second destructor call. The line return my; calls the copy constructor, giving it the variable my to be used to construct the return value. This doesn't generate any output.
my is then destroyed. Once the function call has completed, the return value is destroyed at the end of the line { function();.
In the second case, the copy for the return is elided completely (the compiler is allowed to do this as an optimisation). You only ever have one My instance. (Yes, it is allowed to do this even though it changes the observable behaviour of your program!)
These are both ok. Although as a general rule, if you define your own constructor and destructor, you should also define your own copy constructor (and assignment operator, and possibly move constructor and move assignment if you have c++11).
Try adding your own copy constructor and see what you get. Something like
My (const My& otherMy) { cout << "My copy constructor\n"; }
The problem is that your class My violates the Rule of Three; if you write a custom destructor then you should also write a custom copy constructor (and copy assignment operator, but that's not relevant here).
With:
struct My
{ My() { cout << "My constructor " << endl; }
My(const My &) { cout << "My copy constructor " << endl; }
~My() { cout << "My destructor " << endl; }
};
the output for MSVC is:
My constructor
My function
My copy constructor
My destructor
My destructor
As you can see, (copy) constructors match with destructors correctly.
The output under gcc is unchanged, because gcc is performing copy elision as allowed (but not required) by the standard.
You are missing two things here: the copy constructor and NRVO.
The behavior seen with MSVC++ is the "normal" behavior; my is created and the rest of the function is run; then, when returning, a copy of your object is created. The local my object is destroyed, and the copy is returned to the caller, which just discards it, resulting in its destruction.
Why does it seem that you are missing a constructor call? Because the compiler automatically generated a copy constructor, which is called but doesn't print anything. If you added your own copy constructor:
My(const My& Right) { cout << "My copy constructor " << endl; }
you'd see
My constructor <----+
My function | this is the local "my" object
My copy constructor <--|--+
My destructor <----+ | this is the return value
My destructor <-----+
So the point is: it's not that there are more calls to destructors than constructors, it's just that you are not seeing the call to the copy constructor.
In the gcc output, you are also seeing NRVO applied.
NRVO (Named Return Value Optimization) is one of the few cases where the compiler is allowed to perform an optimization that alters the visible behavior of your program. In fact, the compiler is allowed to elide the copy to the temporary return value, and construct the returned object directly, thus eliding temporary copies.
So, no copy is created, and my is actually the same object that is returned.
My constructor <-- called at the beginning of f
My function
My destructor <-- called after f is terminated, since
the caller discarded the return value of f
To date, I have been designing my classes on the assumption that for each constructor call there will be at most one destructor call [...]
You can still "assume" that since it is true. Each constructor call will go in hand with exactly one destructor call. (Remember that if you handle stuff on the free/heap memory on your own.)
[..] and can be compiler-dependent [...]
In this case it can't. It is optimization depedant. Both, MSVC and GCC behave identically if optimization is applied.
Why don't you see identical behaviour?
1. You don't track everything that happens with your object. Compiler-generated functions bypass your output.
If you want to "follow-up" on the things your compiler does with your objects, you should define all of the special members so you can really track everything and do not get bypassed by any implicit function.
struct My
{
My() { cout << "My constructor " << endl; }
My(My const&) { cout << "My copy-constructor " << endl; }
My(My &&) { cout << "My move-constructor " << endl; }
My& operator=(My const&) { cout << "My copy-assignment " << endl; }
My& operator=(My &&) { cout << "My move-assignment " << endl; }
~My() { cout << "My destructor " << endl; }
};
[Note: The move-constructor and move-assignment will not be implicitly present if you have the copy ones but it's still nice to see when the compiler use which of them.]
2. You don't compile with optimization on both MSVC and GCC.
If compiled with MSVC++11 /O2 option the output is:
My constructor
My function
My destructor
If compiled in debug mode / without optimization:
My constructor
My function
My move-constructor
My destructor
My destructor
I can't do a test on gcc to verify if there's an option that enforces all of these steps but -O0 should do the trick I guess.
What's the difference between optimized and non-optimized compilation here?
The case without any copy omittance:
The completely "non-optimized" behaviour in this line My my_in_main = function();
(changed the name to make things clear) would be:
Call function()
In function construct My My my;
Output stuff.
Copy-construct my into the return value instance.
return and destroy my instance.
Copy(or move in my example)-construct the return value instance into my_in_main.
Destroy the return value instance.
As you can see: we have at most two copies (or one copy and one move) here but the compilers may possibly omit them.
To my understanding, the first copy is omited even without optimization turned on (in this case), leaving the process as follows:
Call function()
In function construct My My my; First constructor output!
Output stuff. Function output!
Copy(or move in my example)-construct the return value instance into my_in_main. Move output!
Destroy the return value instance. Destroy output!
The my_in_main is destroy at the end of main giving the last Destroy output!. So we know what happens in the non-optimized case now.
Copy elision
The copy (or move if the class has a move constructor as in my example) can be elided.
§ 12.8 [class.copy] / 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.
So now the question is when does this happen in this example? The reason for the elison of the first copy is given in the very same paragraph:
[...] in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cvunqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value.
Return type matches type in the return statement: function will construct My my; directly into the return value.
The reason for the elison of the second copy/move:
[...] 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.
Target type matches the type returned by the function: The return value of the function will be constructed into my_in_main.
So you have a cascade here:
My my; in your function is directly constructed into the return value which is directly constructed into my_in_main So you have in fact only one object here and function() would (whatever it does) in fact operate on the object my_in_main.
Call function()
In function construct My instance into my_in_main. Constructor output!
Output stuff. Function output!
my_in_main is still destroyed at the end of main giving a Destructor output!.
That makes three outputs in total: Those you observe if optimization is turned on.
An example where elision is not possible.
In the following example both copies mentioned above cannot be omitted because the class types do not match:
The return statement does not match the return type
The target type does not match the return type of the function
I just created two additional types:
#include <iostream>
using namespace std;
struct A
{
A(void) { cout << "A constructor " << endl; }
~A(void) { cout << "A destructor " << endl; }
};
struct B
{
B(A const&) { cout << "B copy from A" << endl; }
~B(void) { cout << "B destructor " << endl; }
};
struct C
{
C(B const &) { cout << "C copy from B" << endl; }
~C(void) { cout << "C destructor " << endl; }
};
B function() { A my; cout << "function" << endl; return my; }
int main()
{
C my_in_main(function());
return 0;
}
Here we have the "completely non-optimized behaviour" I mentioned above. I'll refer to the points I've drawn there.
A constructor (see 2.)
function (see 3.)
B copy from A (see 4.)
A destructor (see 5.)
C copy from B (see 6.)
B destructor (see 7.)
C destructor (instance in main, destroy at end of main)
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?
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).
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++
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/
I used to think that in C++, if a constructor throws an exception, the destructor of this "partially constructed" class is not called.
But it seems that it is not true anymore in C++11: I compiled the following code with g++ and it prints "X destructor" to the console. Why is this?
#include <exception>
#include <iostream>
#include <stdexcept>
using namespace std;
class X
{
public:
X() : X(10)
{
throw runtime_error("Exception thrown in X::X()");
}
X(int a)
{
cout << "X::X(" << a << ")" << endl;
}
~X()
{
cout << "X destructor" << endl;
}
};
int main()
{
try
{
X x;
}
catch(const exception& e)
{
cerr << "*** ERROR: " << e.what() << endl;
}
}
Output
Standard out:
X::X(10)
X destructor
Standard error:
*** ERROR: Exception thrown in X::X()
Delegating constuctors are indeed a new feature that introduces a new destruction logic.
Let us revisit the lifetime of an object: An object's lifetime begins when some constructor has finished. (See 15.2/2. The standard calls this the "principal constructor".) In your case, this is the constructor X(int). The second, delegating constructor X() acts as just a plain member function now. Upon scope unwinding, the destructors of all fully-constructed objects are called, and this includes x.
The implications of this are actually quite profound: You can now put "complex" work loads into a constructor and take full advantage of the usual exception propagation, as long as you make your constructor delegate to another constructor. Such a design can obviate the need for various "init"-functions that used to be popular whenever it wasn't desired to put too much work into a regular constructor.
The specific language that defines the behaviour you're seeing is:
[C++11: 15.2/2]: [..] Similarly, if the non-delegating constructor for an object
has completed execution and a delegating constructor for that object exits with an exception, the object’s destructor will be invoked. [..]
I used to think that in C++, if a constructor throws an exception, the destructor of this "partially constructed" class is not called.
But it seems that it is not true anymore in C++11
It's still true. Nothing changed since C++03 (for some value of nothing ;-) )
What you thought is still true, but there is no partially constructed object when the exception is thrown.
The C++03 TC1 standard says (emphasis mine):
An object that is partially constructed or partially destroyed will have destructors executed for all of its fully constructed subobjects, that is, for subobjects for which the constructor has completed execution and the destructor has not yet begun execution.
i.e. Any object which has completed its constructor will get destroyed by executing the destructor. That's a nice simple rule.
Fundamentally the same rule applies in C++11: as soon as X(int) has returned, the object's "constructor has completed execution" so it is fully constructed, and so its destructor will run at the appropriate time (when it goes out of scope or an exception is thrown during some later stage of its construction.) It's still the same rule, in essence.
The delegating constructor's body runs after the other constructor and can do extra work, but that doesn't change the fact the object's construction has finished, so it is completely constructed. The delegating constructor is analogous to a derived class' constructor, which executes more code after a base class' constructor finishes. In some sense you can consider your example to be like this:
class X
{
public:
X(int a)
{
cout << "X::X(" << a << ")" << endl;
}
~X()
{
cout << "X destructor" << endl;
}
};
class X_delegating : X
{
public:
X_delegating() : X(10)
{
throw runtime_error("Exception thrown in X::X()");
}
};
it's not really like this, there's only one type, but it's analogous in as much as the X(int) constructor runs, then additional code in the delegating constructor runs, and if that throws the X "base class" (which isn't really a base class) gets destroyed.
I want to be able to throw a constructed object, but modify it just before it's thrown
(using the Named Parameter Idiom).
Given:
#include <iostream>
#include <exception>
using namespace std;
struct my_exception : std::exception {
my_exception() {
cout << "my_exception(): this=" << hex << (unsigned long)this << endl;
}
my_exception( my_exception const& ) {
cout << "my_exception( my_exception const& )" << endl;
}
~my_exception() throw() {
cout << "~my_exception()" << endl;
}
my_exception& tweak() {
return *this;
}
char const* what() const throw() { return "my_exception"; }
};
int main() {
try {
throw my_exception().tweak();
}
catch ( my_exception const &e ) {
cout << "&e=" << hex << (unsigned long)&e << endl;
}
}
When I run the program, I get:
my_exception(): this=7fff5fbfeae0
my_exception( my_exception const& )
~my_exception()
&e=1001000f0
~my_exception()
As you can see, the exception object caught is not the one that's originally thrown.
If I remove the call to tweak(), I instead get:
my_exception(): this=1001000f0
&e=1001000f0
~my_exception()
For the case where tweak() is called, why is the copy constructor called? I want tweak() to operate on the originally constructed object and no copy to be made. Is there any way to prevent the copy construction?
FYI: I'm using g++ 4.2.1 (part of Xcode on Mac OS X).
An exception is thrown by value. You can't throw a reference as a reference. When you try, the object gets copied (using the statically known type).
By the way, this one reason why it's a good idea to make exceptions cloneable, and to have virtual rethrower method.
EDIT (see comments): For example, it's Undefined Behavior to propagate an exception through a C callback. But if you have defined a suitable exception class then you can clone it, and in C++-land again up the call chain rethrow via virtual method.
Cheers & hth.,
To add to Alf's answer, the fact that you aren't getting a copy operation when you don't call tweak() is because the standard permits (but doesn't require) eliding calls to the copy constructor to create the temporary exception object. From C++03 15.1/5 (Throwing an exception):
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).
If you make the copy constructor private, gcc will give you an error (even though when the constructor is public it doesn't get called). MSVC will not give an error, but it should I think.
AFAIK the following happens in your line throw my_exception().tweak(); :
new my_exception object is created (locally, on the stack), tweak() returns reference to this local object. Then, when you throw this reference, you go out of the scope and local object gets deleted. So, the implementation copies the class to dynamic memory to keep reference valid.
In the second case you throw it by value and it is allocated in dynamic memory at once.