Two Calls to Destructor

Destructor called two times in C++

There are 2 A objects created in main, testA, and the A base-subobject of testB. Both are destroyed at the end of main, in reverse order of how they are declared.

class A {
int a, b;
std::string msg;
protected:
A(int x, int y, std::string m) : a(x), b(y), msg(m) {}
public:
A(int x, int y) : A(x, y, "Exit from A\n") {}
virtual ~A() {
std::cout << msg;
}
virtual void values() {
std::cout << a << "\n" << b << std::endl;
}
};

class B :public A
{
int c;
public:
B(int x, int y, int z) : A(x, y, "Exit from B\n"), c(z) {}
void values() override {
A::values();
std::cout << c << std::endl;
}
};

Destructor called twice

The last object is deconstructed two times.

Once when you explicitly destruct it, and then once again when the function ends and all variables local to the function auto-destruct. This is undefined behavior.

You should almost never call a destructor yourself.

Two calls to destructor

Your output doesn't account for the Test's copy constructor, which std::vector is apt to use.

The Test object you see get created is the temporary passed to push_back(), not the one actually in the vector.

Why exactly is calling the destructor for the second time undefined behavior in C++?

Destructors are not regular functions. Calling one doesn't call one function, it calls many functions. Its the magic of destructors. While you have provided a trivial destructor with the sole intent of making it hard to show how it might break, you have failed to demonstrate what the other functions that get called do. And neither does the standard. Its in those functions that things can potentially fall apart.

As a trivial example, lets say the compiler inserts code to track object lifetimes for debugging purposes. The constructor [which is also a magic function that does all sorts of things you didn't ask it to] stores some data somewhere that says "Here I am." Before the destructor is called, it changes that data to say "There I go". After the destructor is called, it gets rid of the information it used to find that data. So the next time you call the destructor, you end up with an access violation.

You could probably also come up with examples that involve virtual tables, but your sample code didn't include any virtual functions so that would be cheating.

Manual call of destructor

Why destructor is called twice.

The first call is from the line i.~Test();.

The second call is the automatic call to the destructor when the variable i gets out of scope (before returning from main).

In first call of destructor memeber value is changed from 6 to 7 , still in second call it comes as 6.

That's caused by undefined behavior. When an object's destructor gets called twice, you should expect undefined behavior. Don't try to make logical sense when a program enters undefined behavior territory.

Can we stop second call of destructor (I want to keep only manually call of destructor).

You can't disable the call to the destructor of an automatic variable when variable goes out of scope.

If you want to control when the destructor is called, create an object using dynamic memory (by calling new Test) and destroy the object by calling delete.

GB::Test* t = new GB::Test(); // Calls the constructor
t->i = 6;
delete t; // Calls the destructor

Even in this case, calling the destructor explicitly is almost always wrong.

t->~Test();  // Almost always wrong. Don't do it.

Please note that if you want to create objects using dynamic memory, it will be better to use smart pointers. E.g.

auto t = std::make_unique<GB::Test>();  // Calls the constructor
t->i = 6;
t.reset(); // Calls the destructor

If t.reset(); is left out, the dynamically allocated object's destructor will be called and the memory will be deallocated when t gets out of scope. t.reset(); allows you to control when the underlying object gets deleted.

Why are there two extra calls to destructor as I have created only two objects and using overloaded assignment operator and increment operator

This is because of

ob3 = ++ob1;

Look at this code more carefully

loc operator++(){
cout<<"inside pre incriment"<

So what can you do to avoid this extra copy.. You can return by reference

const loc&  operator++(){
cout<<"inside pre incriment"<<endl;
++iVAL;
return *this; <--- you create a new copy and send it back
}

The above code returns by reference and the const pointer is prevent others from modifying your value.

However the code you have written for pre increment is wrong
It should retun the value before increment.

So the code should be something like this

loc operator++(){
cout<<"inside pre incriment"<<endl;
int temp = iVAL;
++iVAL;
return temp; <--- you create a new copy and send it back
}

In this case you cannot return by reference between temp is a temporary variable.

Coordinating destructors on two classes, where one class needs to clean up first

If both are declared local in a function, then CDatabase would necessarily be declared first, since CStatement takes it in constructor. Therefore, it'll be destroyed last. Objects with automatic duration are always destroyed in reverse order of construction.

Destructor being called twice when being explicitly invoked

It happens because you told it to happen. The destructor for an automatic variable is always called when the variable goes out of scope. You also called it. That's two calls total.

Calling an object's destructor does not signal to C++ not to call it again, since in normal execution there is no need to keep track.

The solution is to never manually call your destructor.

Strange C++ behaviour involving multiple calls to destructor

This is because nameless temporary objects are being created and destroyed during the course of the program.

Usually, the standard does not provide any guarantees w.r.t creation of temporary objects while using Standard Library containers and Algorithms. Implementations are allowed to create temporary objects if they desire so(for good performance or whatever).

Note that You should follow the Rule of Three in c++03 and Rule of Five in c++11 to avoid any problems due to temporary object creation.



Related Topics



Leave a reply



Submit