Does a destructor gets called before an object is destroyed or after an object is destroyed?
I think that it is called before an object is destroyed because after an object is destroyed we cant access that memory to free any resource in there but if I am wrong then please correct me so I can understand it well
#include <iostream>
#include <cassert>
#include <cstddef>
class Check
{
public:
int neu{};
Check() = default;
Check(int n)
{
neu = n;
}
void print()
{
std::cout << neu << std::endl;
}
~Check()
{
std::cout << "It has been destroyed "<<neu <<std::endl;
}
};
int main()
{
Check let,see(30);
let.print();
return 0;
// does destructor gets called here
} // or does destructor gets called herecode here
Does a destructor gets called before an object is destroyed or after an object is destroyed?
The lifetime of the object has ended when the destructor is called. The object is destroyed by the destructor.
// does destructor gets called here
} // or does destructor gets called herecode here
There's really no practical difference.
The automatic objects are alive within the block and they aren't alive outside the block. The objects are destroyed when the block is exited. As such, it is reasonable to say that they are destroyed at the point where the closing brace is.
From ISO standard (Special member functions - Destructors):
Once a destructor is invoked for an object, the object no longer
exists; the behavior is undefined if the destructor is invoked for an
object whose lifetime has ended.
Destructor call is essentially description of actions need to consider object destroyed. Destructor can be called explicitly, it results in end of life for that object. Explicit calls are rare, usually done for objects created by placement new.
Given the example provided, the question is actually about order of destructor calls. The destructors for sub-objects ( base class-type included, if any present) are called after. So you can safely access them until exit from destructor. Order of call is based on declaration order, just like order of initialization but inverted. Subobject of base-class type is considered the first for initialization and the last for destruction.
Related
This question already has answers here:
Automatic destruction of object even after calling destructor explicitly
(5 answers)
Closed 3 years ago.
This code:
#include <iostream>
class Base { };
class Derived : public Base
{
public:
~Derived()
{
std::cout<< "Derived dtor" << std::endl;
}
};
int main()
{
Derived objD;
objD.~Derived();
return 0;
}
prints:
Derived dtor // destructor called
Derived dtor // printed by 'return 0'
I don't have idea from where comes the second line.
With this main:
int main()
{
Derived objD;
return 0;
}
It prints only one line.
What you have here is undefined behavior as per the C++ standard:
As per [class.dtor]/16
Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended (6.8). [ Example: If the destructor for an automatic object is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined. —end example ]
You explicitly call the destructor for the automatic object objD with this statement:
objD.~Derived();
And the implicit destruction of the object is invoked at the end of its scope the closing }.
You create an object on the stack. This object has automatic lifetime managed by its surrounding scope. If you manually invoke the destructor, you do what the compiler does for you, and you end up with undefined behavior.
you call the destructor, c++ have an automated call for destructor after the main function, or after the object is not in used and then the destructor call. you do double "free"
Object destructors are always called when the object goes out of scope. That's a fundamental part of how C++ is designed, enabling memory-safe exceptions, RAII, etc. Manually calling the destructor first has no bearing on that, so if you call it yourself it will (most likely, this is UB) run twice as you can see.
Calling a destructor manually is almost always incorrect and will result in Undefined Behaviour. The one case where it's allowed is when you've created an object in separately-allocated memory via "placement new".
Suppose I have a class that may run some code asynchronously, and that asynchronous code uses that class instance to do things like call member functions, read data members, etc. Obviously the class instance must outlive the background thread in order for those accesses to be safe. It is sufficient to ensure this by joining the background thread in the destructor? For example:
#include <iostream>
#include <thread>
class foo final
{
public:
foo() = default;
void bar() {
std::cout << "Hopefully there's nothing wrong with using " << this << "\n";
}
void bar_async() {
if (!m_thread.joinable()) {
m_thread = std::thread{&foo::bar, this};
}
}
~foo() {
if (m_thread.joinable()) {
std::cout << "Waiting for " << m_thread.get_id() << "\n";
m_thread.join();
}
}
private:
std::thread m_thread;
};
int main() {
foo f;
f.bar_async();
}
Specifically, I'm worried about object lifetime rules:
For any object of class types whose destructor is not trivial, lifetime ends when the execution of the destructor begins.
... after the lifetime of an object has ended and before the storage which the object occupied is reused or released, the following uses of the glvalue expression that identifies that object are undefined: ...
Access to a non-static data member or a call to a non-static member function.
But to me, a strict reading of the above would also imply that calling this->bar() from inside ~foo() directly is undefined, which is "obviously" not the case.
cppreference is right but it is talking about accessing the members from the object, not from inside the destructor. If we look at [class.cdtor]/1 we see that
For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior. For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.
emphasis mine
So, as long as we are in the destructor we can still work with the member objects as those are not destroyed until the scope of the destructor ends.
So, calling join on the thread is fine here. If you think about it if it wasn't then things like lock guards would be useless if accessing the mutex they refer to was undefined behavior.
My intuition is no. This is because thread::join can throw an exception and you don't want exceptions escaping your destructor. It may be okay if you wrap it in a try catch and handle the exception properly though.
The following program :
#include <iostream>
using namespace std;
class Test
{
public:
Test() { cout << "Constructor is executed\n"; }
~Test() { cout << "Destructor is executed\n"; }
};
int main()
{
Test(); // Explicit call to constructor
Test t; // local object
t.~Test(); // Explicit call to destructor
return 0;
}
prints the following output:
Constructor is executed
Destructor is executed
Constructor is executed
Destructor is executed
Destructor is executed
My question is even after explicitly calling destructor in main(), why does the compiler call the destructor implicitly before exiting main()?
As a side question, apart from use in delete operator is there any other use of the strategy of calling destructor explicitly?
You've introduced undefined behavior.
Per the standard:
§ 12.4 Destructors
(11) A destructor is invoked implicitly
(11.3) — for a constructed object with automatic storage duration (3.7.3) when the block in which an object is
created exits (6.7),
and
15 Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the
destructor is invoked for an object whose lifetime has ended (3.8). [ Example: if the destructor for an
automatic object is explicitly invoked, and the block is subsequently left in a manner that would ordinarily
invoke implicit destruction of the object, the behavior is undefined. —end example ]
You explicitly call the destructor or by calling t.~Test(), it is then implicitly invoked when the object leaves scope. This is undefined.
The standard provides this note as well:
14 [ Note: explicit calls of destructors are rarely needed. One use of such calls is for objects placed at specific
addresses using a placement new-expression. Such use of explicit placement and destruction of objects can
be necessary to cope with dedicated hardware resources and for writing memory management facilities.
This is not an "explicit call to constructor":
Test(); // Explicit call to constructor
It constructs a temporary object, which implicitly calls the constructor, then the temporary immediately goes out of scope, which implicitly calls the destructor. You can't explicitly call a constructor, it gets called implicitly when you construct an object.
My question is even after explicitly calling destructor in main(), why does the compiler call the destructor implicitly before exiting main()?
Because the compiler always destroys local variables. Just because you did something dumb (manually destroyed an object that gets destroyed automatically) doesn't change that.
As a side question, apart from use in delete operator is there any other use of the strategy of calling destructor explicitly?
It's used when managing the lifetime of objects in raw memory, which is done by containers like std::vector and other utilities like std::optional.
My question is even after explicitly calling destructor in main(), why does the compiler call the destructor implicitly before exiting main()?
The destructor will be called when the object gets out of scope, regardless of whether you call the destructor explicitly or not. Don't explicitly call the destructor for objects with automatic storage duration.
As a side question, apart from use in delete operator is there any other use of the strategy of calling destructor explicitly?
Yes. When you initialize an object using the placement new expression, you need to call the destructor explicitly. Sample code from the above site:
char* ptr = new char[sizeof(T)]; // allocate memory
T* tptr = new(ptr) T; // construct in allocated storage ("place")
tptr->~T(); // destruct
delete[] ptr; // deallocate memory
the scope of t is the main function. Its created on the stack and will be destroyed at the end of the function.
That's how its supposed to work and when you call the destructor on it early, you don't change that.
You don't need to call the destructor and in this case doing so leads to it being called twice.
if you'd used
Test* t = new Test();
the destructor would not have been automatically called at the end of main.
The compiler does not care if you called the destructor explicitly or not. The local object t gets out of scope, that's why it gets destroyed and the destructor is called.
It is no good practice to call destructors explicitly. Instead you should write a method like cleanup() that can be called explicitly as well as from within the destructor. If you want to avoid that cleanup can be called twice, add something like this to you class:
private:
bool cleanupPerformed;
void cleanup()
{
if( !cleanupPerformed )
{
// ... do cleanup work here ...
cleanupPerformed = true;
}
}
I have the following code snippet:
#include<iostream>
using namespace std;
class Test {
public:
Test() { cout << "Constructor is executed\n"; }
~Test() { cout << "Destructor is executed\n";}
void show() { this->Test::~Test(); }
};
int main() {
Test t;
t.show();
return 0;
}
Here is the output:
Constructor is executed
Destructor is executed
Destructor is executed
Question: If t.show() has already called the destructor on "this" object(i.e. current object), which causes "destructor is executed" to be displayed once, then what causes it to be displayed for the second time? Which object is getting destroyed in that case ?
Automatic variables get destroyed when they go out of scope. Test t is an automatic variable which goes out of scope when main ends. That's the second time the destructor is being called. The first time is through Test::show since the function manually destroys the object pointed to by this.
Since, C++ follows the philosophy of not paying for what you don't use, there isn't a runtime check of any sort before invoking the destructor on automatic variables going out of scope. Of course, what actually happens on the second destructor call is UB. Beware of nasal demons.
Pradhan has given you an easy to understand explanation, I'll share the particular rule that deals with explicit destructor calls on objects with automatic storage duration, found in section 3.8p8 of the Standard:
If a program ends the lifetime of an object of type T with static, thread, or automatic storage duration and if T has a non-trivial destructor, the program must ensure that an object of the original type occupies that same storage location when the implicit destructor call takes place; otherwise the behavior of the program is undefined. This is true even if the block is exited with an exception.
You're violating this rule, so you get undefined behavior.
The "implicit destructor call" is described in 6.7p2:
Variables with automatic storage duration are initialized each time their declaration-statement is executed. Variables with automatic storage duration declared in the block are destroyed on exit from the
block.
For a simple class like this:
class X {
public:
//...
private:
int *ptr;
};
X::~X() {
delete ptr;
}
I have written a destructor to free the memory pointed to by ptr. Now, I am wondering, if my destructor stays like this, when is ptr actually destroyed?
Thanks
I think this article might answer most of your questions
"Destructors are implicitly called when an automatic object (a local
object that has been declared auto or register, or not declared as
static or extern) or temporary object passes out of scope. They are
implicitly called at program termination for constructed external and
static objects. Destructors are invoked when you use the delete
operator for objects created with the new operator."
More specifically:
"The destructors of base classes and members are called in the reverse
order of the completion of their constructor:
The destructor for a class object is called before destructors for
members and bases are called.
Destructors for nonstatic members are called before destructors for
base classes are called.
Destructors for nonvirtual base classes are called before destructors
for virtual base classes are called."
delete invokes the destructor of the object that is being deleted and then frees the memory it occupied.
The destructor will calls in the end of scope where the specific instance are.
The local version of ptr for a given instance of X will be destroyed when the object goes out of scope. For example:
int main()
{
X obj;
for (int i=0; i<10; i++) {
X tmp;
// do work with tmp
...
// tmp goes out of scope here
// the destructor tmp::~X will be called here, immediately after each iteration ends
}
// obj goes out of scope here
// the destructor obj::~X called when the program ends
}