Is the memory automatically reclaimed when a delegating constructor throws? - c++

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

Related

Throwing an exception in a destructor and subsequent destructors

I did an experiment with throwing an exception from a destructor and got a result that I did not expect. See the code snippet:
#include <iostream>
#include <exception>
class A
{
public:
~A() noexcept(false)
{
std::cout << "in ~A" << std::endl;
//throw std::runtime_error("~A exception");
}
};
class M
{
public:
~M() noexcept(false)
{
std::cout << "in ~M" << std::endl;
//throw std::runtime_error("~M exception");
}
};
class B : public A
{
public:
~B() noexcept(false)
{
std::cout << "in ~B" << std::endl;
throw std::runtime_error("~B exception");
}
private:
M m;
};
class X
{
public:
~X() noexcept(false)
{
std::cout << "in ~X" << std::endl;
//throw std::runtime_error("~X exception");
}
};
int main()
{
try
{
X x;
B b;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
return 0;
}
the output:
in ~B
in ~M
in ~A
in ~X
~B exception
0
so the question is: is this correct that if I throw an exception from a destructor it is caught then all the subsequent destructors (including the destructors of the base class, class members and the destructors of the objects declared on the stack (as X, for example)) are called and then the exception is rethrown?
EDIT1:
The same result if I modify main() as follows:
int main()
{
try
{
X x;
B * b = new B();
delete b;
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
return 0;
}
and then the exception is rethrown?
No, it is not "rethrown". The destructors are being called as part of throwing (and catching) the exception. This is slightly a semantical difference, but an exception gets thrown only once, here, and the objects get destroyed as part of the exception getting thrown.
Let's set aside the issue of throwing exceptions from destructors (which is, in itself, an iffy topic). Consider the following code:
void function()
{
X some_object;
throw std::runtime_error("bad");
}
X's destructor gets called here as part of throwing the exception. Why? Because the object is getting destroyed. The destructor gets called no differently from what it gets called if this function returns normally. The only difference is that instead of returning to the caller, the execution returns to wherever the exception gets caught (presuming that it gets caught). But, either way, execution leaves this scope, which means that the automatically-scoped object must get destroyed, which means that its destructor must get called.
A destructor of an automatically-scoped object gets called whenever execution leaves the object's automatic scope. Whether the scope is left voluntarily, or involuntarily due to a thrown exception, makes no difference.
In your case, this is no different. In fact, your code already entered the most derived-object's destructor as part of destroying it normally (via delete or by leaving the automatic object's scope). The fact that an exception gets thrown does not really change, much, the fact that the objects get destroyed. The only difference is that the object get destroyed as part of throwing an exception, since the execution moves where it gets caught, but whether the execution moves to where it gets returned or, or where its exception gets caught, makes no difference with regards to the destructor invocation.

Why deallocation function is not called when object constructor throw in a new expression?

If I define operator delete as following and if an object constructor throw in the new expression I expected to see the result of the call to the defined operator delete:
#include <new>
#include <cstdlib>
#include <iostream>
void*
operator new(std::size_t s){
std::cout << "alloc " << std::endl;
return std::malloc(s);
}
void
operator delete(void* p) noexcept {
std::cout << "dealloc " << std::endl;
std::free(p);
}
void
operator delete(void* p,std::size_t) noexcept{
std::free(p);
std::cout << "dealloc s" << std::endl;
}
struct A{
A(int i){
if(i>0)
throw 10;
}
};
int main(int argc// will equal 10
,char* arg[])
{
for(int i=0;i<argc;++i)
auto p=new A{argc};
return 0;
}
This program just output alloc, why the operator delete are not called? In the standard [expr.new] it is specified that:
If any part of the object initialization described above 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, after which the exception continues to propagate in the context of the new-expression.
As others already noted, it is because you do not catch the exception. As the standard notes:
C++11 §15.3/9:
“If no matching handler is found, the function std::terminate() is called; whether or not the stack is unwound before this call to std::terminate() is implementation-defined.”
While I think this is not specifically related to the stack in your case, the same principle will hold here, too. So it is actually up to the implementation if any memory is cleaned up. As we see here, it is usually not the case, because the operating system cleans up the memory anyway.
If you fix your code to throw exception, it works as expected:
int main(int argc,char* arg[])
{
try {
new A(2);
}
catch (...)
{}
}
Demo
If during construction using new, a constructor throws an exception, the C++ runtime library:
calls std::terminate() if no suitable catch handler is found. Whether or not delete is called is implementation defined.
or
calls delete for you before "sending" that exception to the suitable catch handler if one is found, although the destructor is not called - i.e. ~A(), if you had one, would not be called when i is greater than 1.

Constructor finishes by throwing an exception ? Is there a memory leak?

I was going over this article
and it states
Note: if a constructor finishes by throwing an exception, the memory
associated with the object itself is cleaned up — there is no memory
leak. For example:
void f()
{
X x; // If X::X() throws, the memory for x itself will not leak
Y* p = new Y(); // If Y::Y() throws, the memory for *p itself will not leak
}
I am having difficulty understanding this and would appreciate it if someone could clarify this. I tried the following example which shows that incase of an exception inside a constructor the destructor would not be called.
struct someObject
{
someObject()
{
f = new foo();
throw 12;
}
~someObject()
{
std::cout << "Destructor of someobject called";
}
foo* f;
};
class foo
{
public:
foo()
{
g = new glue();
someObject a;
}
~foo()
{
std::cout << "Destructor of foo";
}
private:
glue* g;
};
int main()
{
try
{
foo a;
}
catch(int a)
{
//Exception caught. foo destructor not called and someobject destrucotr not called.
//Memory leak of glue and foo objects
}
}
How would I fix this issue ?
Sorry for the inconvenience the update might have caused.
"... the destructor would not be called."
Since the object isn't considered as constructed yet, after the constructor failed with an exception, the destructor won't be called.
Object allocation, and construction (merely destruction) are different things.
Any objects allocated using new() before the exception is thrown will leak.
You shouldn't manage these resources yourself, unless you're really, really, really need it, and are about 100% sure about what you're doing.
Rather use suitable smart pointers for class members from the standard dynamic memory management library.
When the constructor throws, no destructor will be called. When an
exception is thrown inside a constructor there are several things that
you should take note of in terms of properly handling resource
allocations that may have occured in the aborted construction of the
object:
the destructor for the object being constructed will not be called.
destructors for member objects contained in that object's class will be called
the memory for the object that was being constructed will be freed.

Destructor not invoked when an exception is thrown in the constructor

Why is the destructor not invoked in this code?
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; throw; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
int main()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
std::cout << myinst->increment() << '\n';
std::cout << myinst->increment() << '\n';
}
EDIT
From the answers, In understand that when an exception happens in the constructor, destructor will not be invoked. But if the exception happens in the main(), ie after the MyClass object is fully instantiated, will the MyClass destructor be invoked? If not, then why it is a smart pointer?
Adding the code
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
int main()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
throw 3;
std::cout << myinst->increment() << '\n';
std::cout << myinst->increment() << '\n';
}
Output:
MyClass Allocated
terminate called after throwing an instance of 'int'
Aborted
A C++ object's lifetime begins only after its constructor completes successfully.
Since the exception was thrown before constructor call was complete you don't have an complete object and hence no destructor.
Herb Sutter explains this nicely, to quote him:
Q: What does emitting an exception from a constructor mean?
A: It means that construction has failed, the object never existed, its lifetime never began. Indeed, the only way to report the failure of construction -- that is, the inability to correctly build a functioning object of the given type -- is to throw an exception. (Yes, there is a now-obsolete programming convention that said, "if you get into trouble just set a status flag to 'bad' and let the caller check it via an IsOK() function." I'll comment on that presently.)
In biological terms,
conception took place -- the constructor began -- but despite best efforts it was followed by a miscarriage -- the constructor never ran to term(ination).
Incidentally, this is why a destructor will never be called if the constructor didn't succeed -- there's nothing to destroy. "It cannot die, for it never lived." Note that this makes the phrase "an object whose constructor threw an exception" really an oxymoron. Such a thing is even less than an ex-object... it never lived, never was, never breathed its first. It is a non-object.
We might summarize the C++ constructor model as follows:
Either:
(a) The constructor returns normally by reaching its end or a return statement, and the object exists.
Or:
(b) The constructor exits by emitting an exception, and the object not only does not now exist, but never existed as an object.
EDIT 1:
But if the exception happens in the main(), ie after the MyClass object is fully instantiated, will the MyClass destructor be invoked?
Yes, it will be!
That is the purpose of using scoped_ptr, Once an exception is thrown in main, Stack Unwinding would cause all local objects to be deallocated, this means that myinst(which resides on stack) will also be deallocated, which in turn will call the destructor of MyClass.
Refer the Boost doccumentation when in doubt:
The scoped_ptr class template stores a pointer to a dynamically allocated object. (Dynamically allocated objects are allocated with the C++ new expression.) The object pointed to is guaranteed to be deleted, either on destruction of the scoped_ptr, or via an explicit reset
EDIT 2:
Why does your edited program crash?
Your program shows crashes because, You throw an exception but you never catch it. when such a scenario occurs an special function called terminate() is called whose default behavior is to call abort().It is implementation defined behavior whether stack is Unwound before terminate() is called in this particular scenarioRef 1.Seems your implementation doesn't & you should not rely on this behavior as well.
You can modify your program as follows to handle the exception and you should get the behavior you were expecting:
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
void doSomething()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
throw 3;
}
int main()
{
try
{
doSomething();
}
catch(int &obj)
{
std::cout<<"Exception Handled";
}
}
Ref1C++03 15.5.1 The terminate() function
In the following situations exception handling must be abandoned for less subtle error handling techniques:
....
— when the exception handling mechanism cannot find a handler for a thrown exception (15.3),
....
In such cases,
void terminate();
is called (18.6.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before terminate() is called. In all other situations, the stack shall not be unwound before terminate() is called. An implementation is not permitted to finish stack unwinding prematurely based on a determination that the unwind process will eventually cause a call to terminate().
Because calling the destructor doesn't make sense in this case.
You only destruct things which are constructed, yet your object never fully constructs. Your class members have been constructed, though, and will have their destructors called.
If a constructor throws exception, then the destructor of the class will not be called, because the object is not fully constructed.
See this link how to manage resources in such situation:
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10
When the exception is thrown from the constructor (beginning or half way or at the end of the call), then it's assured that the object is not constructed.
So it's well defined not to invoke the destructor of an object which was never constructed.
Here is one related FAQ from Bjarne's website.
The destructor for MyClass was never invoked because no objects of type MyClass were ever constructed. Each attempt to construct one was aborted, due to the exception being thrown.
As an aside, if you want your debug messages to display -- especially if you're dealing with the program crashing -- you really ought to flush the streams: i.e. using std::endl instead of '\n' at the end of line. (or inserting std::flush)
While merely using '\n' often works, there are enough situations where it fails and it's really, really confusing to debug if you don't make a habit of doing things right.

What happens if delete[] p fails?

Suppose I have a pointer to a dynamically allocated array of 10 elements:
T* p = new T[10];
Later, I want to release that array:
delete[] p;
What happens if one of the T destructors throws an exception? Do the other elements still get destructed? Will the memory be released? Will the exception be propagated, or will program execution be terminated?
Similarly, what happens when a std::vector<T> is destroyed and one of the T destructors throws?
I can not see it explicitly called out in the standard:
Just that they will be called in reverse order of creation
5.3.5 Delete [expr.delete]
6 If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will invoke the destructor (if any) for the object or the elements of the array being deleted. In the case of an array, the elements will be destroyed in order of decreasing address (that is, in reverse order of the completion of their constructor; see 12.6.2).
And that the memory deallocation will be done even if the exception is thrown:
7 If the value of the operand of the delete-expression is not a null pointer value, the delete-expression will call a deallocation function (3.7.4.2). Otherwise, it is unspecified whether the deallocation function will be called. [ Note: The deallocation function is called regardless of whether the destructor for the object or some element of the array throws an exception. — end note ]
I tried the following code in G++ and it shows that that no more destructors get called after the exception:
#include <iostream>
int id = 0;
class X
{
public:
X() { me = id++; std::cout << "C: Start" << me << "\n";}
~X() { std::cout << "C: Done " << me << "\n";
if (me == 5) {throw int(1);}
}
private:
int me;
};
int main()
{
try
{
X data[10];
}
catch(...)
{
std::cout << "Finished\n";
}
}
Execute:
> g++ de.cpp
> ./a.out
C: Start0
C: Start1
C: Start2
C: Start3
C: Start4
C: Start5
C: Start6
C: Start7
C: Start8
C: Start9
C: Done 9
C: Done 8
C: Done 7
C: Done 6
C: Done 5
Finished
Which all leads back to this (very old answer):
throwing exceptions out of a destructor
5.3.5.7 If the value of the operand of the
delete-expression is not a null
pointer value, the delete-expression
will call a deallocation function
(3.7.3.2). Otherwise, it is unspecified
whether the deallocation function will
be called. [ Note: The deallocation
function is called regardless of
whether the destructor for the object
or some element of the array throws an
exception. — end note ]
Couldn't find anything about destructors except for
In the case of an array, the elements will be
destroyed in order of decreasing address (that is, in reverse order of the completion of their constructor; see 12.6.2).
I guess that after throwing no more destructors are called, but I'm not sure.
Never do that. If there is already an active exception, std::terminate will be called: "Bang, you're dead". Your destructor must. Not. Throw. Resist.
edit: Relevant section from the Standard (14882 2003), 15.2 Constructors and Destructors [except.dtor] :
15.2.3 The process of calling destructors for automatic objects constructed on the path from a try block to a
throw-expression is called “stack unwinding.” [Note: If a destructor called during stack unwinding exits with an exception, terminate is called (15.5.1). So destructors should generally catch exceptions and
not let them propagate out of the destructor. —end note]
Testcase for playing around (in real life, throw something that is derived from std::exception, never throw int or something else!):
#include <iostream>
int main() {
struct Foo {
~Foo() {
throw 0; // ... fore, std::terminate is called.
}
};
try {
Foo f;
throw 0; // First one, will be the active exception once Foo::~Foo()
// is executed, there- ...
} catch (int) {
std::cout << "caught something" << std::endl;
}
}
To answer your second question, if you used std::vector instead, there wouldn't be any need for a call to delete, you're not using pointers (the vector class is internally I believe, but this is not up to you to manage).
Okay, here is some experimental code:
#include <cstddef>
#include <cstdlib>
#include <new>
#include <iostream>
void* operator new[](size_t size) throw (std::bad_alloc)
{
std::cout << "allocating " << size << " bytes" << std::endl;
return malloc(size);
}
void operator delete[](void* payload) throw ()
{
std::cout << "releasing memory at " << payload << std::endl;
free(payload);
}
struct X
{
bool throw_during_destruction;
~X()
{
std::cout << "destructing " << (void*)this << std::endl;
if (throw_during_destruction) throw 42;
}
};
int main()
{
X* p = new X[10]();
p[5].throw_during_destruction = true;
p[1].throw_during_destruction = true;
delete[] p;
}
Running the code gave the following output on g++ 4.6.0:
allocating 14 bytes
destructing 0x3e2475
destructing 0x3e2474
destructing 0x3e2473
destructing 0x3e2472
destructing 0x3e2471
terminate called after throwing an instance of 'int'
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
So it would seem that std::terminate is called immediately as soon as the first destructor throws. The other elements are not destructed, and the memory is not released. Can anyone confirm this?
If an exception is thrown, it is thrown. The object that failed to destruct is obviously not properly destroyed, and neither are the ones remaining in the array.
If you use a vector, the problem is the same, just not in your code. :-)
So, throwing destructors is just a Bad Idea(tm).
Like #Martin shows below, the object that did thrown is formally non-existent as soon as we enter the destructor. The others might have their memory reclaimed as well.
However, it obviously contained some complicated things that were not properly of flusher flushed. If that object, and the others following it in the array, contained some mutex locks, open files, database caches, or shared_ptrs, and none of those had their destructors run, we are likely in BIG trouble.
Having std::terminate called at that point, to put the program out of its misery, seems like something you would wish for!