I am using RAII and using try/catch to not leak memory for example. Here is an implementation in C++:
#include <iostream>
using namespace std;
void g(){
throw 5;
}
class Rand{
public:
~Rand(){
cout << "Randomm Destructor called" << endl;
}
int a = 17;
};
void f(){
auto p = std::make_unique<Rand>(); //Should call dtor
Rand* r = new Rand(); //Shouldnt call dtor
cout << p->a << endl; //Prints 17
g();
cout << "This never executes" << endl;
}
int main(){
f();
}
Due to stackunwinding and using RAII with the std::unique_ptr, shouldn't the destructors for stack allocated objects be called as a basic guarantee to throw/try since an exception is being thrown?
From throw:
Stack unwinding
As the control flow moves up the call stack, destructors are invoked
for all objects with automatic storage duration constructed, but not
yet destroyed, since the corresponding try-block was entered, in
reverse order of completion of their constructors.
There is no corresponding try-block in your code, so no destructors are called and the program is terminated.
If you change the program as:
try
{
auto p = std::make_unique<Rand>(); //Should call dtor
Rand* r = new Rand(); //Shouldnt call dtor
cout << p->a << endl; //Prints 17
g();
cout << "This never executes" << endl;
}
catch (int) {}
you will see, that the destructor for the object which is wrapped into unique_ptr is called.
Related
I was trying to create an object inside static function using a constructor.
Here is the code
class A {
public:
A() { this->a = 50; std::cout << "constructor called... " << this << std::endl; setAddr(this); }
~A() { this->a = 10; std::cout << "destructor called... " << this << std::endl; }
int a;
static A* addr;
static void setAddr(A* ad) { addr = ad; }
static A &create() { A(); return *addr; }
};
A* A::addr = NULL;
int main() {
A &ptr = A::create();
std::cout << "a = " << ptr.a << std::endl;
ptr.a = 100;
std::cout << "a = " << ptr.a << std::endl;
getch();
return 0;
}
I know using new is best way to do it,but i was trying to do it using contructor to know whether it can be done or not.
The output was:
constructor called... 009AF874
destructor called... 009AF874
a = 10
a = 100
Now here is my question,
1) why destructor is called when did not create an object using any declaration like A obj;
2) and if the destructor is called then how I am able to assign a value to otr.a;
By looking at the program's output I made the following conclusion.
1) I read somewhere that constructor is called after the memory has been allocated to object. And if an object is created then it has to be destroyed and the scope of the obj decided to destroy it now.
2) Since object address has previous values before destroying it and returns call return the address of the variable storing it. When I try to access it, I was able to do so because that memory address still exists.
That's not how you make a singleton. The statement
A();
creates a temporal object of class A that is destroyed (as per standard) at end of statement.
Indeed, memory is allocated before call of constructor. Resulting object can be assigned or passed by reference or value to any function of this statement, but in former case, reference is valid only until end of call expression. Exception is that if it was assigned to reference, its length of life is extended to one
of reference. After life of object ended, any access to memory it used results in UB, provided that it could be used by any other operations.
Any access to object after destructor was called is an UB as well.
Here is an example (this code intentionally contains UB)
#include <iostream>
class A {
public:
A() { this->a = 50; std::cout << "constructor called... " << this << std::endl; }
~A() { this->a = 10; std::cout << "destructor called... " << this << std::endl; }
int a;
static const A &create() {
const A& addr = A();
std::cout << "a = " << addr.a << std::endl;
return addr;
}
};
int main() {
const A &ref = A::create();
std::cout << "a = " << ref.a << std::endl;
return 0;
}
Note, that C++ allows to bind temporary only to const reference. There are way to work around that, but that's irrelevant.
Output of this program may vary, depending on compiler and level of optimization. E.g. clang with no optimization:
constructor called... 0x7ffc1f7991d0
a = 50
destructor called... 0x7ffc1f7991d0
a = 4202884
gcc may output 10 in last line. MS may crash on it. Keyword is "may", there is no rule that governs what would happen. Object stopped existing after create() returned reference to it because lifespan of addr came to end, and we are left with dangling reference.
Obviously we can extend lifespan of addr by making it static.
static const A &create() {
static const A& addr = A();
std::cout << "a = " << addr.a << std::endl;
return addr;
}
Static variable in function's scope will be created at first call of function and stops to exist when process stops.
constructor called... 0x6031b8
a = 50
a = 50
destructor called... 0x6031b8
What happens, in the following code, if construction / destruction of some array element throws?
X* x = new X[10]; // (1)
delete[] x; // (2)
I know that memory leaks are prevented, but additionally:
Ad (1), are the previously constructed elements destructed? If yes, what happens if destructor throws in such a case?
Ad (2), are the not-yet-destructed elements destructed? If yes, what happens if destructor throws again?
Yes, if the constructor of x[5] throws, then the five array elements x[0]..x[4] already successfully constructed will be destroyed correctly.
Destructors should not throw. If a destructor does throw, this happens while the previous (constructor) exception is still being handled. As nested exceptions aren't supported, std::terminate is called immediately. This is why destructors shouldn't throw.
There are two mutually-exclusive options here:
If you reach label (2), the constructor didn't throw. That is, if x was successfully created, all ten elements were successfully constructed. In this case, yes, they all get deleted. No, your destructor still shouldn't throw.
If the constructor threw part-way through step (1), then the array x never really existed. The language tried to create it for you, failed, and threw an exception - so you don't reach (2) at all.
The key thing to understand is that x either exists - in a sane and predictable state - or it doesn't.
The language doesn't give you some un-usable half-initialized thing, if a constructor failed, because you couldn't do anything with it anyway. (You couldn't even safely delete it, because there would be no way to track which of the elements were constructed, and which were just random garbage).
It might help to consider the array as an object with ten data members. If you're constructing an instance of such a class, and one of the base-class or member constructors throws, all the previously-constructed bases and members are destroyed in exactly the same way and your object never starts existing.
We can test with the following code:
#include <iostream>
//`Basic` was borrowed from some general-purpose code I use for testing various issues
//relating to object construction/assignment
struct Basic {
Basic() {
std::cout << "Default-Constructor" << std::endl;
static int val = 0;
if(val++ == 5) throw std::runtime_error("Oops!");
}
Basic(Basic const&) { std::cout << "Copy-Constructor" << std::endl; }
Basic(Basic &&) { std::cout << "Move-Constructor" << std::endl; }
Basic & operator=(Basic const&) { std::cout << "Copy-Assignment" << std::endl; return *this; }
Basic & operator=(Basic &&) { std::cout << "Move-Assignment" << std::endl; return *this; }
~Basic() noexcept { std::cout << "Destructor" << std::endl; }
};
int main() {
Basic * ptrs = new Basic[10];
delete[] ptrs;
return 0;
}
This code yields the following output before crashing:
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
[std::runtime_error thrown and uncaught here]
Note that at no point were the Destructors called. This isn't necessarily a critical thing, since an uncaught exception will crash the program anyways. But if we catch the error, we see something reassuring:
int main() {
try {
Basic * ptrs = new Basic[10];
delete[] ptrs;
} catch (std::runtime_error const& e) {std::cerr << e.what() << std::endl;}
return 0;
}
The output changes to this:
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
Default-Constructor
Destructor
Destructor
Destructor
Destructor
Destructor
Oops!
So Destructors will be automatically called for fully constructed objects, even without an explicit delete[] call, because the new[] call has handling mechanisms to deal with this.
But you do have to worry about that sixth object: in our case, because Basic doesn't do any resource management (and a well-designed program wouldn't have Basic do resource management if its constructor could throw like this), we don't have to worry. But we might have to worry if our code looks like this instead:
#include <iostream>
struct Basic {
Basic() { std::cout << "Default-Constructor" << std::endl; }
Basic(Basic const&) { std::cout << "Copy-Constructor" << std::endl; }
Basic(Basic &&) { std::cout << "Move-Constructor" << std::endl; }
Basic & operator=(Basic const&) { std::cout << "Copy-Assignment" << std::endl; return *this; }
Basic & operator=(Basic &&) { std::cout << "Move-Assignment" << std::endl; return *this; }
~Basic() noexcept { std::cout << "Destructor" << std::endl; }
};
class Wrapper {
Basic * ptr;
public:
Wrapper() : ptr(new Basic) {
std::cout << "WRDefault-Constructor" << std::endl;
static int val = 0;
if(val++ == 5) throw std::runtime_error("Oops!");
}
Wrapper(Wrapper const&) = delete; //Disabling Copy/Move for simplicity
~Wrapper() noexcept { delete ptr; std::cout << "WRDestructor" << std::endl; }
};
int main() {
try {
Wrapper * ptrs = new Wrapper[10];
delete[] ptrs;
} catch (std::runtime_error const& e) {std::cout << e.what() << std::endl;}
return 0;
}
Here, we get this output:
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Oops!
The large block of Wrapper objects will not leak memory, but the sixth Wrapper object will leak a Basic object because it was not properly cleaned up!
Fortunately, as is usually the case with any resource-management scheme, all these problems go away if you use smart pointers:
#include <iostream>
#include<memory>
struct Basic {
Basic() { std::cout << "Default-Constructor" << std::endl; }
Basic(Basic const&) { std::cout << "Copy-Constructor" << std::endl; }
Basic(Basic &&) { std::cout << "Move-Constructor" << std::endl; }
Basic & operator=(Basic const&) { std::cout << "Copy-Assignment" << std::endl; return *this; }
Basic & operator=(Basic &&) { std::cout << "Move-Assignment" << std::endl; return *this; }
~Basic() noexcept { std::cout << "Destructor" << std::endl; }
};
class Wrapper {
std::unique_ptr<Basic> ptr;
public:
Wrapper() : ptr(new Basic) {
std::cout << "WRDefault-Constructor" << std::endl;
static int val = 0;
if(val++ == 5) throw std::runtime_error("Oops!");
}
//Wrapper(Wrapper const&) = delete; //Copy disabled by default, move enabled by default
~Wrapper() noexcept { std::cout << "WRDestructor" << std::endl; }
};
int main() {
try {
std::unique_ptr<Wrapper[]> ptrs{new Wrapper[10]}; //Or std::make_unique
} catch (std::runtime_error const& e) {std::cout << e.what() << std::endl;}
return 0;
}
And the output:
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Default-Constructor
WRDefault-Constructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
WRDestructor
Destructor
Oops!
Note that the number of calls to Destructor now match the number of calls to Default-Constructor, which tells us that the Basic objects are now getting properly cleaned up. And because the resource management that Wrapper was doing has been delegated to the unique_ptr object, the fact that the sixth Wrapper object doesn't have its deleter called is no longer a problem.
Now, a lot of this involves strawmanned code: no reasonable programmer would ever have a resource manager throw without proper handling code, even if it were made "safe" by use of smart-pointers. But some programmers just aren't reasonable, and even if they are, it's possible you might come across a weird, exotic scenario where you have to write code like this. The lesson, then, as far as I'm concerned, is to always use smart pointers and other STL objects to manage dynamic memory. Don't try to roll your own. It'll save you headaches exactly like this when trying to debug things.
So we have a constructor that can throw an exception depending on the arguments passed to it, but we do not know how to delete the object if this occurs. Important part of the code:
try
{
GameBase *gameptr = GameBase::getGame(argc, argv);
if (gameptr == 0)
{
std::cout << "Correct usage: " << argv[PROGRAM_NAME] << " " << "TicTacToe" << std::endl;
return NO_GAME;
}
else
{
gameptr->play();
}
delete gameptr;
}
catch (error e)
{
if (e == INVALID_DIMENSION)
{
std::cout << "Win condition is larger than the length of the board." << std::endl;
return e;
}
}
catch (...)
{
std::cout << "An exception was caught (probably bad_alloc from new operator)" << std::endl;
return GENERIC_ERROR;
}
In the third line, GameBase::getGame() calls the constructor for one of the games derived from GameBase and returns a pointer to that game, and these constructors can throw exceptions. The question is, how can we then delete the (partial?) object pointed to by gameptr if this occurs? If an exception is thrown, we will exit the scope of gameptr because we leave the try block and cannot call delete gameptr.
To assess the exception safety, you need to provide more detail of the construction of the object in GameBase::getGame.
The rule is through, that if a constructor throws, the object is not created, hence the destructor is not called. Associated memory allocations are also deallocated (i.e. the memory for the object itself).
The issue then becomes, how was the memory allocated to begin with? If it was with a new GameBase(...), then there is no need to deallocate or delete the resultant pointer - the memory is deallocated by the runtime.
For clarity on what happens to the member variables that are already constructed; they are destructed on the exception of the "parent" object. Consider the sample code;
#include <iostream>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
M m_;
C() { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
auto main() -> int {
try {
C c;
}
catch (exception& e) {
cout << e.what() << endl;
}
}
The output is;
M ctor
C ctor
M dtor
std::exception
If the M m_ member is to be dynamically allocated, favour a unique_ptr or a shared_ptr over a naked pointer, and allow the smart pointers to manage the object for you; as follows;
#include <iostream>
#include <memory>
using namespace std;
struct M {
M() { cout << "M ctor" << endl; }
~M() { cout << "M dtor" << endl; }
};
struct C {
unique_ptr<M> m_;
C() : m_(new M()) { cout << "C ctor" << endl; throw exception(); }
~C() { cout << "C dtor" << endl; }
};
The output here mirrors the output above.
When you write Foo* result = new Foo(), the compiler translates this to the equivalent of this code:
void* temp = operator new(sizeof(Foo)); // allocate raw memory
try {
Foo* temp2 = new (temp) Foo(); // call constructor
result = temp2;
} catch (...) {
operator delete(temp); // constructor threw, deallocate memory
throw;
}
So you don't need to worry about the allocated memory if the constructor throws. Note, however, that this does not apply to extra memory allocated within the constructor. Destructors are only called for objects whose constructor finished, so you should get all your allocations into small wrapper objects (smart pointers) immediately.
If you throw in a constructor, the object is not constructed and thus, you are responsible for the deletion of allocated resources. This goes even further! Consider this Code
int a = function(new A, new A);
It is up to the compiler in which ordering is the A allocated AND constructed. You might end up with an memory leak, if your A constructor can throw!
Edit:
Use instead
try{
auto first = std::make_unique<A>();
auto second = std::make_unique<A>();
int a = function(*first, *second);
...
The output of the program below is:
begin try
Object() ctor
begin catch
Why is the Holder class's destructor not called? Is this a memory leak? Is it possible to call the Holder class's destructor without rethrowing?
#include <iostream>
#include <exception>
class Object
{
public:
Object() { std::cout << "Object() ctor" << std::endl; }
~Object() { std::cout << "~Object() dtor" << std::endl; }
};
class Holder
{
public:
Holder() :myObjectP( new Object() )
{
throw std::exception();
}
~Holder()
{
std::cout << "~Holder()" << std::endl;
delete myObjectP;
}
private:
Object* myObjectP;
};
int main(int argc, char* argv[])
{
try
{
std::cout << "begin try" << std::endl;
Holder h;
}
catch ( ... )
{
std::cout << "begin catch" << std::endl;
}
return 0;
}
In this case, your Holder object h is not fully constructued, that is that h's constructor had not finished its construction before the stack unwinding process had begun.
C++11 15.2 Constructors and destructors
(2)
An object of any storage duration whose initialization or destruction
is terminated by an exception will have destructors executed for all
of its fully constructed subobjects (excluding the variant members of
a union-like class), that is, for subobjects for which the principal
constructor (12.6.2) has completed execution and the destructor has
not yet begun execution.
I know Object *pObject=new Object contain two steps:
operator new to allocate memory
call object's constructor.
and call delete pObject:
call object's destruct;
operator delete to free memory.
But when new Object process, if the step 2 throw exception, if the operator delete be called to free memory by system?
No, the destructor is not called. As the object isn't constructed properly it would be unsafe to call the destructor. However if any member objects have been constructed fully then they are destructed (as the object is complete).
Some people recommend against throwing in constructors, I believe it is better than zombie states which is akin to error codes and makes verbose code. So long as you follow RAII you should be fine (each resource is managed by it's own object). Before you throw in the constructor make sure that you clean up anything you've half done, but again, if you're using RAII that should be nothing.
The following outputs "B":
#include <iostream>
struct B {
~B() { std::cout << "B" << std::endl; }
};
struct A {
A() : b() { throw(1); }
~A() { std::cout << "A" << std::endl; }
B b;
};
int main() {
try {
A *a = new A;
delete a;
} catch(int a) {}
}
Edit:
The above isn't what you asked, yes the delete operator is called, http://www.cplusplus.com/reference/new/operator%20delete[] says:
"These deallocation functions are called by delete-expressions and by new-expressions to deallocate memory after destructing (or failing to construct) objects with dynamic storage duration."
This could be tested by overriding the operator delete.
Yes, the operator delete will be called to release the memory allocated.
The program below can prove that:
#include <iostream>
using std::cout;
using std::endl;
class A {
public:
A() { cout << "A() at " << this << endl; throw 1; }
~A() { cout << "~A() at " << this << endl; }
};
int main(int argc, char *argv[]) {
int N = 3;
for (int i = 0; i < N; ++i) {
try {
new A;
} catch (int a) {
// pass
}
}
return 0;
}
Running this program on my system, I find that the result printed out are like this:
A() at 0x2170010
A() at 0x2170010
A() at 0x2170010
Obviously, the destructors are NOT call because NO
~A() at 0x2170010
lines are printed out.
And the operator delete are surely called because the addresses of the three objects are exactly the same.