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
}
Related
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.
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;
}
}
What happens when you delete a pointer to an object of a class that does not have a declared destructor?
Every class (or struct) has a destructor (unless it is a POD. If you do not declare one the compiler will add an implicit destructor. Take the following class as an example:
struct A
{
std::string test;
};
No destructor was defined for A. Yet it has one, because the compiler automatically adds it. It isn't even empty. It would call the destructor of test, because std::string has a destructor itself.
According to the C++ Standard (12.4 Destructors)
4 If a class has no user-declared destructor, a destructor is
implicitly declared as defaulted (8.4). An implicitlydeclared
destructor is an inline public member of its class.
11... A destructor is also invoked implicitly through use of a delete- expression (5.3.5) for a constructed object allocated by a new-expression (5.3.4);
And all destructors do the following except that implicitly defined destructor has an empty body and consequently does not have automatic objects allocated within its body.
8 After executing the body of the destructor and destroying any
automatic objects allocated within the body, a destructor for class X
calls the destructors for X’s direct non-variant non-static data
members, the destructors for X’s direct base classes and, if X is the
type of the most derived class (12.6.2), its destructor calls the
destructors for X’s virtual base classes. All destructors are called
as if they were referenced with a qualified name, that is, ignoring
any possible virtual overriding destructors in more derived classes.
Bases and members are destroyed in the reverse order of the completion
of their constructor (see 12.6.2). A return statement (6.6.3) in a
destructor might not directly return to the caller; before
transferring control to the caller, the destructors for the members
and bases are called. Destructors for elements of an array are called
in reverse order of their construction (see 12.6).
I assume that by delete a pointer p to a class C you mean
C *p;
<some init and work>
delete p;
If class C does not have a destructor explicitly declared the compiler will add a destructor implicitly.
This implicitly destructor gets called upon destruction of an instance of
the class doing nothing.
n.b. the implicitly added destructor is inline public.
Implicitly-declared destructor
If no user-defined destructor is provided for a class type (struct, class, or union), the compiler will always declare a destructor as an inline public member of its class.
Deleted implicitly-declared destructor
The implicitly-declared or defaulted destructor for class T is undefined (until C++11)defined as deleted (since C++11) if any of the following is true:
T has a non-static data member that cannot be destructed (has deleted or inaccessible destructor)
T has direct or virtual base class that cannot be destructed (has deleted or inaccessible destructors)
T is a union and has a variant member with non-trivial destructor.
(since C++11)
The implicitly-declared destructor is virtual (because the base class has a virtual destructor) and the lookup for the deallocation function (operator delete() results in a call to ambiguous, deleted, or inaccessible function.
#include <iostream>
struct A
{
int i;
A ( int i ) : i ( i ) {}
~A()
{
std::cout << "~a" << i << std::endl;
}
};
int main()
{
A a1(1);
A* p;
{ // nested scope
A a2(2);
p = new A(3);
} // a2 out of scope
delete p; // calls the destructor of a3
}
output:
~a2
~a3
~a1
On the last line of a destructor, I have a diagnostic type message which takes a printf-like form:
"object destroyed at %p", this
I have concerns though about how well this is defined at such a point.
Should I have such reservations? Is the behaviour well-defined?
According to the C++ Standard (12.4 Destructors)
8 After executing the body of the destructor and destroying any
automatic objects allocated within the body, a destructor for class
X calls the destructors for X’s direct non-variant non-static data
members, the destructors for X’s direct base classes and, if X is the
type of the most derived class (12.6.2), its destructor calls the
destructors for X’s virtual base classes.
So your code is well-formed. All destructors of non-static data members and base classes are called after executing the body of the destructor.
Well, the pointer itself certainly still exists (it's just an address, after all). There should be no problem to print the pointer value.
On the other hand, everything that you did in the destructor has already happened. Attributes may already have been delete'd, etc, so you have to avoid anything that accesses those.
This has perfectly well defined behaviour. Consider that the this pointer can be used implicitly or explicitly throughout the destructor, e.g. whenever you access a member variable for things like delete ptr_;. After the destructor returns, the members are destroyed in reverse order of declaration/creation then the base destructors invoked.
As you might now, you can access your class members from the destructor. This would not be working if the this pointer was invalid. So you can safely assume that the address this points to is still the same that you might have printed in the constructor.
Inside the destructor the this pointer is well defined, as are all the members and bases (that will be destroyed in construction reverse order after the destructor return). So printing the address it refers is not UB.
The only thing is that the object itself cannot be assumed anymore as "polymorphic", since the derived components had already been destroyed.
class A
{
public:
virtual void fn() { std::cout << "A::fn" << std::endl; }
virtual ~A() { fn(); } //< will call A::fn(), even if B is destroying
};
class B: public A
{
public:
virtual void fn() { std::cout << "B::fn" << std::endl; }
virtual ~B() {}
};
int main()
{
B b;
A& a = b;
a.fn(); //< will print B::fn(), being A::fn virtual and being B the runtime-type of the a's referred object
return 0; //< will print A::fn() from b's A's component destructor
}
Does the default destructor in C++ classes automatically delete members that are not explicitly allocated in code? For example:
class C {
public:
C() {}
int arr[100];
};
int main(void) {
C* myC = new C();
delete myC;
return 0;
}
Does delete myC deallocate myC's arr automatically? Or do I need to write C's destructor to do this explicitly?
The constructor (in the absence of any ctor-initializer-list) calls the default constructor for each subobject.
Since you have no base classes and your member variables are primitive types, it will do nothing at all.
Same with the destructor. Yours is implicitly compiler-generated since you haven't declared one, and it will call the destructor for each subobject. Again that's trivial because your only subobject is an aggregate of primitives.
Now, all memory of the class will be freed when you delete it. Since the array is embedded inside the class, it's part of the same memory region and will be freed at the same time.
The implicitly defined (default) destructor will call the destructor for each member. In the case of a member array, it will call the destructor for each element of the array.
Note that pointers don't have destructors; you need to manually delete them. You don't have this problem in the provided example, but it's something to be aware of.
If your class/struct contains a pointer, and you explicitly allocate something for that pointer to refer to, then you normally need to write a matching delete in the dtor. Members that are directly embedded into the class/struct will be created and destroyed automatically.
class X {
int x;
int *y;
public:
X() : y(new int) {}
~X() : { delete y; }
};
Here X::x will be created/destroyed automatically. X::y (or, to be technically correct, what X::y points at) will not -- we allocate it in the ctor and destroy it in the dtor.
Anything that you call new for must have a corresponding delete. If you didn't call new to create an instance of something then you don't have to call delete.
You don't have to write a destructor. C++ class has the default destructor to delete the object after 'return 0' to recycle the memory.