Behaviour of explicit call to destructor - c++

The definition of some_class is:
class some_class
{
// stuff
public:
~some_class()
{
delete dynamic_three;
}
private:
classA one;
classB two;
classC* dynamic_three;
}
When the lifetime of a object ends, its destruction is: (1) to call its destructor and (2) to destroy its subobjects in the same order on which they are declared in the class definition (= position in memory).
But, if I have something like that:
auto* ptr = new some_class();
// more stuff
ptr->~some_class(); // l. X
The step (2) is also realized? I mean, in line X, are destructors of subobjects also called or only is executed the body of the some_class's destructor?

The step (2) is also realized?
Yes, it’s guaranteed. The behaviour is safe, but note that in your case you have no way of safely reclaiming the memory of the object without re-constructing it first via placement-new (unless you overladed operator new for your object and you can thus guarantee how the memory was allocated and use the matching deallocation).

Let's make a test:
class classA
{
public:
~classA() { cout << "~classA()" << endl; }
};
class classB
{
public:
~classB() { cout << "~classB()" << endl; }
};
class some_class
{
public:
~some_class() { cout << "~some_class()" << endl; }
private:
classA one;
classB two;
};
int main()
{
cout << "Start..." << endl;
auto* ptr = new some_class();
ptr->~some_class();
cout << "End." << endl;
}
Output:
Start...
~some_class()
~classB()
~classA()
End.
So the all destructors are called and in reverse order.

When the lifetime of a object ends, its destruction is: (1) to call its destructor and (2) to destroy its subobjects in the same order on which they are declared in the class definition (= position in memory).
and (3) the allocated memory is freed.
The step (2) is also realized?
Step (2) yes, but not step (3).
But if you can write
auto* ptr = new some_class();
note that you can also write
std::unique_ptr<ptr> ptr (new some_class());
which would call delete for you (of course, only use this if this matches your needs, but use this by default if you are not sure).

Related

Why does the base class pointer point to the pure virtual method in the base class instead of the overidden method in the derived class?

#include <iostream>
class A
{
public:
virtual ~A() = default;
virtual void foo(void) = 0;
};
class B : public A
{
private:
int x;
public:
B(int a) : x(a) {}
void foo(void) { std::cout << "B: " << x << "\n"; }
};
class Foo
{
private:
A* a_ptr;
public:
Foo (B& x) { a_ptr = &x; }
A* get_ptr(void) { return a_ptr; }
void dummy(void) { std::cout << "Foo: "; std::cout << a_ptr << "\t "<< typeid(*a_ptr).name() << "\n"; a_ptr->foo(); std::cout << "\n"; }
};
int main(void)
{
B b(10);
Foo f(b);
f.dummy();
return 0;
}
If the constructor of Foo takes a reference to an object of B, then this program executes the way I expect it to, i.e. a_ptr->foo() calls B::foo().
However, if the constructor is changed to accept the parameter by value, then a_ptr->foo() resolves to A::foo(), and results in a pure virtual method called exception
Sample output (Passed by reference:):
Foo: 0x7fffe90a24e0 1B
B: 10
Sample output (Passed by value):
Foo: 0x7fffc6bbab20 1A
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
I've a vague hunch as to why this might be happening, and I'm looking for some literature or reference which might prove or disprove my hypothesis: When passed by reference, the base class pointer a_ptr points to an entity whose lifetime exceeds past the call to a_ptr->foo().
However, when passed by value, a_ptr points to a temporary which is lost when the constructor exits.
I suppose this has something to do with the VTABLE of A, but I can't quite put my finger on it.
Yes, your suspicion is correct.
When the B object is passed by value into the Foo constructor, it becomes a local variable of the constructor. The constructor is saving a pointer to that local object, which goes out of scope when the constructor exits.
So, the call to a_ptr->foo() in Foo::dummy() is actually undefined behavior since a_ptr doesn't even point at a valid object to begin with. But, it doesn't really crash since A::foo() doesn't use its this pointer for anything. It just points to a compiler-defined function that throws the pure virtual method called error, which you don't catch, so your program terminates.
You assigned temporary object B by reference to a_ptr which is of type A*. On constructor exit this temporary object has beed destroyed. As VTABLE has been destroyed too, called A::foo, which is pure virtual. So you got it.

i need to know how compiler work with destructors in cpp

Lets say I have 2 diffrent classes.
Why when I put class A object as data member inside class B, the class that getting destroyed first is class B and then class A but when i put class A object in the builder of class B then class A getting destroyed first and then class B? for example:
class A {
public:
~A() { std::cout << "Deleting A\n"; }
};
class B {
private:
A object;
public:
~B() { std::cout << "Deleting B\n"; }
};
int main( void ) {
B test;
return 0;
}
result:
Deleting B
Deleting A
But the next example gives me the opposite result :
class A {
public:
~A() { std::cout << "Deleting A\n"; }
};
class B {
public:
B() { A object; }
~B() { std::cout << "Deleting B\n"; }
};
int main( void ) {
B test;
return 0;
}
result:
Deleting A
Deleting B
In your second example B test; calls the constructor of B.
The constructor B is just a function and it has a local variable A object;. This object is created and at the end of the scope (end of the constructor of B) it is detroyed.
Back in main at the end of main the object test is destroyed.
So in that case the object A object; is destroyed first, later object B test; is destroyed.
In your first example this is something different. There A object; is a member of class B, so the constructor of B is constructing the member automatically. The order of construction is: base classes first (not present in your example), then members, then the body of the constructor. Destruction is the opposite order: body of the destructor first, then the members (including your A object;), then the base classes (not present in your example).
As already said in a comment, you can easily step through the code in a debugger to get a better understanding of the order of execution.
Because the object of class A is destroyed as soon the constructor of class B finishes (because it is a local variable inside a function) and it is before the class B destructor be called.
In the second example you've got your object (instance of Class A), local in your Constructor. When you now instantiate B in your main function, the constructor is called, creates object, and destroys it, as sonn as the constructor has finished.
In your first example, object is a class member and lives as long as your class object in your main function. When the programm is finished it calls your costum Destructor, this is then executed first, then it destructs all members (standard Constructor).

How to not delete a copy of base class object?

My problem is, that when I'm using inheritance class, my base class is deleting 2 times (the copy from inheritance too). Is there a chance to not make a copy of base class? Or not delete it?
#include <iostream>
using namespace std;
class base {
public:
base() { cout << "*B"; }
~base() { cout << "~B"; }
};
class restaurant : virtual public base {};
int main() {
base* d1 = new base;
restaurant restaurant;
delete d1;
return 0;
}
The output is *B*B~B~B but I would like to have *B*B~B because I'm not deleting restaurant, only base object.
You're not deleteing restaurant, but you didn't new it either; it's allocated in automatic storage ("the stack"), not dynamic storage ("the heap"). Objects in automatic storage have their destructor called when they go out of scope. This is why the restaurant destructor is still being called in this case.
If you'd written:
restaurant *restaurant = new restaurant;
you'd see the behaviour you're expecting. Of course, by calling new without a matching delete you will be leaking the object, so this is not recommended.
Firstly, objects with automatic storage are automatically deleted a the end of a scope. So declaring restaurant restaurant; will construct a restaurant but will also delete it automatically at the end of the main function.
Try this:
struct A {
A() { std::cout << "A()"; }
~A() { std::cout << "~A()"; }
};
struct B : A {
B() { std::cout << "B()"; }
~B() { std::cout << "~B()"; }
};
auto main() -> int {
B b;
} // b destroyed here
The output is:
A()B()~B()~A()
It behave like a stack. First, the base class is constructed, then the derived class. Then, it destroy the derived first and the base class at the end.
This behaviour is extremely important for most C++ idiom.
Consider this:
struct A {
A() : arr(new int[3]{1, 2, 3}) {}
~A() { delete[] arr; }
int* arr = nullptr;
};
struct B : A {
B() {}
~B() {}
auto stuff() -> int {
return std::accumulate(arr, arr + 3, 0);
}
};
auto main() -> int {
B b;
return b.stuff(); // returns 1 + 2 + 3
}
What would happen if the constructor A() was not executed first? The array would be null. That would be bad.
Also... what would happen if the destructor ~A() was not executed? That would be a memory leak. That would be super bad.
Constructors and destructors have a guaranteed execution and a well defined order. This is why you don't have to call super() and ~super() in all of you constructors and destructor. Because you could forget to call it. Destructor and constructor is not something you want to forget to call, or else there would be no advantages over just using free function like in C.
The output is expected output.
I have added comments in your main function code.
int main() {
//Create base class object and constructor will be called
//This object is allocated on heap
base* d1 = new base;
//Create derived class object
//first constructor of base and then derived (if defined) will be called
//This object is allocated on stack
restaurant restaurant;
//Free memory and Call destructor of base class object
delete d1;
return 0;
//After bracket, stack object will go out of scope and destructor will be called.
//First derived (if defined) class destructor and then base class destructor.
}
To get expected output : *B*B~B
restaurant *restaurant = new restaurant;
But if you don't delete it then it will create memory leak in your program.

Override delete operator with empty implementation

Using the delete operator on an object normally leads to two things: calling the object's destructor (and its virtual base destructors, if present) and freeing the memory afterwards.
If override the delete operator on a class giving it an empty implementation {}, the destructor will still be called, but the memory does not get freed.
Assuming the destructor is also empty, will the delete then have any effect or would it be safe to continue using the "deleted" object (i.e. is there undefined behaviour)?
struct Foo {
static void operator delete(void* ptr) {}
Foo() {}
~Foo() {}
void doSomething() { ... }
}
int main() {
Foo* foo = new Foo();
delete foo;
foo->doSomething(); // safe?
}
Not that this would make much sense as it is, but I'm investigating in a "deferred delete" (gc) mechanism where objects won't get deleted instantly when delete gets called but shortly afterwards.
Update
Referring to some answers that mention memory leaks: let's assume the overloaded delete operator is not empty, but does store its ptr argument in a (let's say static, for the sake of simplicity) set:
struct Foo {
static std::unordered_set<void*> deletedFoos;
static void operator delete(void* ptr) {
deletedFoos.insert(ptr);
}
Foo() {}
~Foo() {}
}
And this set gets cleaned up periodically:
for (void* ptr : Foo::deletedFoos) {
::operator delete(ptr);
}
Foo::deletedFoos.clear();
From n4296:
A destructor is invoked implicitly
(11.1) — for a constructed object with static storage duration (3.7.1)
at program termination (3.6.3),
(11.2) — for a constructed object with thread storage duration (3.7.2)
at thread exit,
(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),
(11.4) — for a constructed temporary object when its lifetime ends
(12.2).
In each case, the context of the invocation is the context of the
construction of the object. 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); the context of the invocation
is the delete-expression. [ Note: An array of class type contains
several subobjects for each of which the destructor is invoked. —end
note ] A destructor can also be invoked explicitly.
Thus, the very use of delete expression that calls delete operator, you implicitly call destructor as well. Object's life ended, it's an undefined behavior what happens if you will call a method for that object.
#include <iostream>
struct Foo {
static void operator delete(void* ptr) {}
Foo() {}
~Foo() { std::cout << "Destructor called\n"; }
void doSomething() { std::cout << __PRETTY_FUNCTION__ << " called\n"; }
};
int main() {
Foo* foo = new Foo();
delete foo;
foo->doSomething();
// safe? No, an UB. Object's life is ended by delete expression.
}
Output:
Destructor called
void Foo::doSomething() called
used: gcc HEAD 8.0.0 20170809 with -O2
The question starts with assumption that redefining delete operator and behaviour of object would omit destruction of object. Redefining destructor of object itself will not redefine destructors of its fields.
In fact it won't exist anymore from semantics point of view. It will not deallocate memory, which might be a thing if object is stored in memory pool. But it would delete abstract 'soul' of object, so to say. Calling methods or accessing fields of object after that is UB.
In particular case, depending on operation system, that memory may stay forever allocated. Which is an unsafe behavior. It also unsafe to assume that compiler would generate sensible code. It may omit actions altogether.
Let me add some data to object:
struct Foo {
int a;
static void operator delete(void* ptr) {}
Foo(): a(5) {}
~Foo() { std::cout << "Destructor called\n"; }
void doSomething() { std::cout << __PRETTY_FUNCTION__ << "a = " << a << " called\n"; }
};
int main() {
Foo* foo = new Foo();
delete foo;
foo->doSomething(); // safe?
}
Output:
Destructor called
void Foo::doSomething() a= 566406056 called
Hm? We didn't initialized memory? Let's add same call before destruction.
int main() {
Foo* foo = new Foo();
foo->doSomething(); // safe!
delete foo;
foo->doSomething(); // safe?
}
Output here:
void Foo::doSomething() a= 5 called
Destructor called
void Foo::doSomething() a= 5 called
What? Of course, compiler just omitted initialization of a in first case. Could it be because class doesn't do anything else? In this case it is possible. But this:
struct Foo {
int a, b;
static void operator delete(void* ptr) {}
Foo(): a(5), b(10) {}
~Foo() { std::cout << "Destructor called\n"; }
void doSomething() { std::cout << __PRETTY_FUNCTION__ << " a= " << a << " called\n"; }
};
int main() {
Foo* foo = new Foo();
std::cout << __PRETTY_FUNCTION__ << " b= " << foo->b << "\n";
delete foo;
foo->doSomething(); // safe?
}
will generate similar undefined value:
int main() b= 10
Destructor called
void Foo::doSomething() a= 2017741736 called
Compiler had considered field a unused by the time of death of foo and thus "dead" without impact on further code. foo went down with all "hands" and none of them formally do exist anymore. Not to mention that on Windows, using MS compiler those programs would likely crash when Foo::doSomething() would try to revive the dead member. Placement new would allow us to play Dr.Frankenstein role:
#include <iostream>
#include <new>
struct Foo {
int a;
static void operator delete(void* ptr) {}
Foo() {std::cout << __PRETTY_FUNCTION__ << " a= " << a << " called\n"; }
Foo(int _a): a(_a) {std::cout << __PRETTY_FUNCTION__ << " a= " << a << " called\n"; }
~Foo() { std::cout << "Destructor called\n"; }
void doSomething() { std::cout << __PRETTY_FUNCTION__ << " a= " << a << " called\n"; }
};
int main() {
Foo* foo = new Foo(5);
foo->~Foo();
Foo *revenant = new(foo) Foo();
revenant->doSomething();
}
Output:
Foo::Foo(int) a= 5 called
Destructor called
Foo::Foo() a= 1873730472 called
void Foo::doSomething() a= 1873730472 called
Irregardless to wit if we call destructor or not, compilers are allowed to decide that revenant isn't same thing as original object, so we can't reuse old data, only allocated memory.
Curiously enough, while still performing UB, if we remove delete operator from Foo, that operation seem to work as expected with GCC. We do not call delete in this case, yet removal and addition of it changes compiler behavior, which, I believe, is an artifact of implementation.
From N4296 (~C++14):
3.8 Object lifetime [basic.life]
...
The lifetime of an object of type T ends when:
(1.3) — if T is a class type with a non-trivial destructor (12.4), the destructor call starts, or
(1.4) — the storage which the object occupies is reused or released.
Then:
12.4 Destructors [class.dtor]
...
A destructor is trivial if it is not user-provided and if:
(5.4) — the destructor is not virtual,
(5.5) — all of the direct base classes of its class have trivial destructors, and
(5.6) — for all of the non-static data members of its class that are of class type (or array thereof), each such class has a trivial destructor.
Otherwise, the destructor is non-trivial.
So basically, for simple enough classes, this is safe, but if you have any kind of resource-owning classes involved it is not going to be legal.
Take care, though, that in your example your destructor is user-provided, hence non-trivial.
Whether your hack can work depends on the members of the class. The destructor will always call the destructors of the class members. If you have any members that are strings, vectors, or other objects with an 'active' destructor, these objects will be destroyed, even tough the memory allocated for the containing object is still allocated.
The main problem is that even if have empty dtor's, other background things, like the release of virtual method tables, will happen. My personal approach in such cases is to make a private dtor and use a member method (name it destroy if you want) for filtering the delete operator. For example
class A
{
bool _may_be_deleted;
public:
A(bool may_be_deleted)
: _may_be_deleted(may_be_deleted){;}
void allow_delete()
{
_prevent_delete = false;
}
static bool destroy(A*);
private:
virtual ~A(){;}
};
bool A::destroy(A *pA)
{
if(pA->_may_be_deleted)
{
delete pA;
return true;
}
return false;
}
int main(int argc, char* argv[])
{
A* pA = new A(false);
A::destroy(pA); //returns false and A is not deleted
pA->allow_delete();
A::destroy(pA); //Ok, now A is destroyed and returns true;
}
Hope that helps.

Is destructor a normal function call?

Lets say I have two simple classes like this with non-virtual destructors:
struct A
{
~A() { std::cout << "A destructor" << std::endl; }
}
struct B : A
{
~B() { std::cout << "B destructor" << std::endl; }
}
When an instance of B is destructed, the destructor of A is called as well. When I destruct an instance of B through a pointer of type A* then Bs destructor will not be called. Does this also count for explicitly calling the destructor in a way you would also call a normal member function?
struct A
{
~A() { std::cout << "Hello" << std::endl; }
void f() { std::cout << "Hello" << std::endl; }
}
A a;
a.~A(); // case 1
a.f(); // case 2
In this example, is there any difference between the two cases other than the name of the function that is called?
EDIT: Consider the same example with CRTP:
template <typename C>
struct A
{
~A() { static_cast<C*>(this)->~C(); }
}
struct B : public A<B>
{
~B() { std::cout << "B destructor" << std::endl; }
}
A<B>* a = new B();
delete a;
Would this cause undefined behaviour or a memory leak?
If you want to explicitly call a destructor, it has to be called from an object of the same type as the destructor being called. Otherwise, this will yield undefined behavior:
In an explicit destructor call, the destructor name appears as a ~
followed by a type-name or decltypespecifier that denotes the
destructor’s class type. The invocation of a destructor is subject to
the usual rules for member functions (9.3); that is, if the object is
not of the destructor’s class type and not of a class derived from the
destructor’s class type (including when the destructor is invoked via
a null pointer value), the program has undefined behavior.
Also note that if explicitly calling a destructor, at the end of the scope where the instance resides, the destructor will implicitly be called a second time, provided that the object has been instanciated on the stack. That also yields undefined behavior:
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
I suggest you read section 12.4 of the spec. The working draft is freely available.
In fact, there are cases (i.e.: when using pools to avoid constant memory allocation), where you would normally call the destructor as a normal function, otherwise it would lead to undefined behaviour when you try to use placement new again on that memory address.
T* Pool::alloc() {
...
return new (memory) T();
}
void Pool::dealloc( T* memory ) {
...
memory->~T();
}
Regarding to the non virtual destructor issue, if the destructor is not virtual, deleting a B object inside a pointer to A, would lead to undefined behaviour.
struct A
{
~A() { std::cout << "A destructor" << std::endl; }
};
struct B : A
{
~B() { std::cout << "B destructor" << std::endl; }
};
A* a = new B();
delete a; // undefined behaviour, just ~A() will be called
B* b = new B();
delete b; // it's OK because b is B*
More info in this FAQ