Exception class copy constructor - c++

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.

Related

Move constructor is not called when throwing an exception

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

An exception gets thrown twice from a constructor with a function-try-block

Why does the following exception thrown from the constructor of class A get caught twice, first by the catch within the constructor itself and second time by the catch in the main function?
Why doesn't it get caught just once by the catch within the constructor?
#include <iostream>
using namespace std;
class E {
public:
const char* error;
E(const char* arg) : error(arg) { }
};
class A {
public:
int i;
A() try : i(0) {
throw E("Exception thrown in A()");
}
catch (E& e) {
cout << e.error << endl;
}
};
int main() {
try {
A x;
}
catch(...)
{
cout << "Exception caught" << endl;
}
}
If I remove the try-catch block in the main function, the program will crash.
Here is the output:
Exception thrown in A()
terminate called after throwing an instance of 'E'
zsh: abort (core dumped) ./main
Why does it crash without the try-catch block in the main function?
Function-try-blocks in a constructor cannot prevent exceptions. Once an exception occurs in a constructor, you have no object, and the exception must propagate. The only thing the function-try-block can do is some local clean-up.
Constructors are indeed a very special animal with regards to function-try-blocks.
Cf. C++11 15.3/14:
The currently handled exception is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor.
Tl;dr: Do not use function-try-blocks, ever.
It seems logical. Consider two following scenarios.
i. Try block is inside constructor's body:
A() : i(0) {
try
{
throw E("Exception thrown in A()");
}
catch (E& e) {
cout << e.error << endl;
}
// If code reaches here,
// it means the construction finished well
}
ii. Try block is in initializer ctor:
A() try : i(0) {
throw E("Exception thrown in A()");
}
catch (E& e) {
cout << e.error << endl;
// OK, you handled the exception,
// but wait you didn't construct the object!
}
In the first case, after an exception, you will handle it inside the constructor and then you will construct the object properly.
In the second case, after an exception you will handle it there. BUT you didn't construct the object yet and you have no object in the caller's side. The caller should handle an un-constructed object situation.
You are utilizing a feature called function-try-catch. When used in a constructor, it allows catching exceptions in the initialization list (especially useful for catching exceptions in base class constructors) as well as the constructor body. But since the exception is thrown in a constructor, the class is incomplete, so the compiler automatically rethrows any caught exception.
that is why you see it caught twice.
Read the following article for more details:
Constructors and Exception in C++

Is the memory automatically reclaimed when a delegating constructor throws?

Following on from this: Is the destructor called when a delegating constructor throws?
class X
{
public:
X() {};
X(int) : X() { throw std::exception(); }
X(double) { throw std::exception(); }
~X();
};
What about dynamic memory? Normally an exception in the constructor means the object was not fully constructed and thus the memory is cleanedup and not lost.
But the argument in the previous question is that the object is fully constructed (or fully initialized) after the delegate completes. How does this affect reclaiming the memory? I would hope that memory is still cleanedup!
int main()
{
new X(5); // new called
// delete called because delegate completed.
// I assume:
// Memory re-claimed (because constructor did not complete)
// I assume the C++11 standard adjusted to compensate.
// As a constructor did complete.
}
Compared too:
int main()
{
new X(5.0); // new called
// Delete **NOT** called
// Memory re-claimed (because constructor did not complete)
}
If the memory is cleaned up, then the definition of when the memory is cleanup needs to be altered from C++03 spec. How is the behavior changed?
If the constructor called by new throws an exception then the memory allocated by new is automatically deallocated. Delegating constructors change nothing in this regard.
If any part of the object initialization described above76 terminates by throwing an exception and a suitable deallocation function can be found, the deallocation function is called to free the memory in which the object was being constructed
                                                                                                       — C++11 [expr.new] 5.3.4/18
The 'any part of the object initialization' described includes both the constructor calls and evaluation of the expressions passed to the constructor.
Also, this behavior is specified identically in the C++98 standard [C++98 5.4.3/17]. The only difference delegating constructors make is if your mental model was previously based on the object being completely constructed or not. Given delegating constructors that's no longer equivalent to the actual specification of when deallocation occurs.
In your first example:
new X(5);
The order of events is:
allocation function called
X(int) called
X() called (and exits successfully)
X(int) throws an exception
~X() called
X(int) exits via exception
deallocation function called because object initialization failed
exception continues to propagate normally
With the second example
new X(5.0);
allocation function called
X(double) called
X(double) fails with an exception
deallocation function called because object initialization failed
exception continues to propagate normally
You can observe this behavior by replacing the allocation and deallocation functions:
#include <iostream>
#include <cstdlib>
#include <stdexcept>
#include <new>
void *operator new(std::size_t s) {
if (void *ptr = std::malloc(s)) {
std::cout << "allocation\n";
return ptr;
}
throw std::bad_alloc{};
}
void operator delete(void *ptr) noexcept {
if (ptr) {
std::cout << "deallocation\n";
std::free(ptr);
}
}
struct S {
S() {};
S(int) : S{} { throw std::exception(); }
S(double) { throw std::exception(); }
~S() { std::cout << "destructor\n"; }
};
int main() {
std::cout << "test 1\n";
try {
new S(1);
} catch(...) {
std::cout << "exception caught\n";
}
std::cout << "test 2\n";
try {
new S(1.);
} catch(...) {
std::cout << "exception caught\n";
}
}
The correct output of this program is:
test 1
allocation
destructor
deallocation
exception caught
test 2
allocation
deallocation
exception caught

Order of subobject destruction when an exception is thrown from the constructor

This question is inspired by Using an object after it's destructor is called
Let's consider the following code
class B
{
public:
B() { cout << "Constructor B() " << endl; }
~B() { cout << "Destructor ~B() " << endl; }
};
class A {
public:
B ob;
A()
try
{
throw 4;
}
catch(...)
{
cout << "Catch in A()\n";
}
A(int)
{
try
{
throw 4;
}
catch(...)
{
cout << "Catch in A(int)\n";
}
}
};
int main()
{
try
{
A f;
}
catch (...)
{
cout << "Catch in main()\n\n";
}
A g(1);
}
It's output is
Constructor B()
Destructor ~B()
Catch in A()
Catch in main()
Constructor B()
Catch in A(int)
Destructor ~B()
In contrast to A(int), constructor A() has the initializer list try/catch syntax. Why that makes a difference on the order of the subobject destruction? Why the exception thrown in A() propagates to main()?
Why that makes a difference on the order of the subobject destruction?
When catch in A(int) - all subobjects are alive, and you can use them. Moreover, after catch, you can continue object construction, and "return" to user properly constructed object.
When catch in A() - all subobjects, which were constructed - are destructed. And you don't know which subobjects were constructed and which not - at least with current ISO C++ syntax.
Why the exception thrown in A() propagates to main()?
Check GotW #66:
If the handler body contained the statement "throw;" then the catch block would obviously rethrow whatever exception A::A() or B::B() had emitted. What's less obvious, but clearly stated in the standard, is that if the catch block does not throw (either rethrow the original exception, or throw something new), and control reaches the end of the catch block of a constructor or destructor, then the original exception is automatically rethrown.
Think about what this means: A constructor or destructor function-try-block's handler code MUST finish by emitting some exception. There's no other way. The language doesn't care what exception it is that gets emitted -- it can be the original one, or some other translated exception -- but an exception there must be! It is impossible to keep any exceptions thrown by base or member subobject constructors from causing some exception to leak beyond their containing constructors.
In fewer words, it means that:
If construction of any base or member subobject fails, the whole object's construction must fail.
The difference is that at the end of:
A()
try
{
throw 4;
}
catch(...)
{
cout << "Catch in A()\n";
}
the exception is implicitly rethrown and no object A get constructed, whereas in:
A(int) {
try
{
throw 4;
}
catch(...)
{
cout << "Catch in A(int)\n";
}
}
you swallow the exception and an instance of A is fully constructed.
Destructors run only on fully constructed objects, that is objects whose constructor finished successfully, without throwing an exception.
EDIT: as per the destruction of subobjcets, the catch in the first case is run after the sub-object has been destructed. This is consistent with the member initialization syntax that suggests that it is what should actually happen:
A()
try : ob() // default construct
{
throw 4;
}
catch(...)
{
// here ob is already destructed
cout << "Catch in A()\n";
}
(equivalent to the first case.)
Why that makes a difference on the order of the subobject destruction?
In general, in the function catch clause of A(), you wouldn't know which members had been successfully constructed, because the exception might have come from one of their constructors. So to remove doubt they're destroyed first. Basically the function try/catch is "outside" the data member construction.
Why the exception thrown in A() propagates to main()?
The function catch clause can't make the constructor succeed (because if its members weren't constructed successfully, then the object itself hasn't been constructed successfully). So if you don't throw something else from it then the original exception is rethrown. That's just how it's defined, you can't use a function-try clause to ignore the problem. You can use a regular try/catch inside a function to ignore a problem, then it's up to you to decide whether or not the problem has prevented the object from being correctly constructed.

Thrown object copy constructs -- why?

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.