Is destructor a normal function call? - c++

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

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.

Is it necessary to have virtual destructor if the derived class only contains automatic variable members?

struct base
{
base(){}
~base() { cout << "base destructor" << endl; }
};
struct derived : public base
{
derived() : base() { vec.resize(200000000); }
~derived() { cout << "derived destructor" << endl; }
vector<int> vec;
};
int main()
{
base* ptr = new derived();
delete ptr;
while (true)
{
}
}
The above code leaks due to delete operation not calling derived object's destructor. But...
struct base
{
base() {}
~base() { cout << "base destructor" << endl; }
};
struct derived : public base
{
derived() : base() {}
~derived() { cout << "derived destructor" << endl; }
int arr[200000000];
};
int main()
{
base* ptr = new derived();
delete ptr;
while (true)
{
}
}
In second case, the memory doesn't leak despite the base destructor is only being called. So I'm assuming it's safe to not have a base destructor if all my members are automatic variables? Doesn't 'arr' member in derived class never go out of scope when derived object's destructor is not being called? What's going on behind the scenes?
YES!
I see that you are thinking "practically", about what destructions might be missed. Consider that the destructor of your derived class is not just the destructor body you write — in this context you also need to consider member destruction, and your suggestion may fail to destroy the vector (because the routine non-virtually destroying your object won't even know that there is a derived part to consider). The vector has dynamically allocated contents which would be leaked.
However we don't even need to go that far. The behaviour of your program is undefined, period, end of story. The optimiser can make assumptions based on your code being valid. If it's not, you can and should expect strange sh!t to happen that may not fit with how your expectation of a computer should work. That's because C++ is an abstraction, compilation is complex, and you made a contract with the language.
It is always necessary to have a virtual destructor in a base class if a derived object is ever deleted through a pointer to that base. Otherwise behaviour of the program is undefined. In any other case it is not necessary to have a virtual destructor. It is irrelevant what members the class has.
It's not necessary to have a memory leak and still invoke an UB. Memory leak is a kind of expected UB if your derived class isn't trivial. Example:
#include <iostream>
class Field {
public:
int *data;
Field() : data(new int[100]) {}
~Field() { delete[] data; std::cout << "Field is destroyed"; }
};
class Base {
int c;
};
// Derived class, contains a non-trivial non-static member
class Core : public Base
{
Field A;
};
int main()
{
Base *base = new Core;
delete base; // won't delete Field
}
he C++ Standard, [expr.delete], paragraph 3 states (2014 edition)
In the first alternative (delete object), if the static type of the
object to be deleted is different from its dynamic type, the static
type shall be a base class of the dynamic type of the object to be
deleted and the static type shall have a virtual destructor or the
behavior is undefined. In the second alternative (delete array) if the
dynamic type of the object to be deleted differs from its static type,
the behavior is undefined.
In reality , if base class is trivial, all fields are trivial and derived class contains no non-static or non-trivial members, one might argue, that those classes are equal, but I'm yet to find way how to prove that through standard.It's likely an IB instead of UB.

Static type of the exception object

I read the following from C++ Primer (5th edition, Section 18.1.1):
"When we throw an expression, the static, compile-time type of that expression determines the type of the exception object." So I tried the following code:
#include <iostream>
class Base{
public:
virtual void print(std::ostream& os){os << "Base\n";}
};
class Derived: public Base{
public:
void print(std::ostream& os){os << "Derived\n";}
};
int main(){
try{
Derived d;
Base &b = d;
b.print(std::cout); //line 1
throw b;
}
catch(Base& c){
c.print(std::cout); //line 2
}
return 0;
}
which gives me the following output:
Derived
Base
I think I understand why this output is expected: at line 1, we have dynamic binding. Now when we throw b, it is based on the static type of b, which means both the static type and the dynamic type of c is Base&, and therefore we see the result at line 2.
However, if I were to use a pointer, instead of a reference:
int main(){
try{
Derived d;
Base *b = &d;
b->print(std::cout); //line 1
throw b;
}
catch(Base* c){
c->print(std::cout); //line 2
}
return 0;
}
the output now becomes:
Derived
Derived
which seems to imply that the static type of c is Base*, but the dynamic type of c is Derived*, why? Shouldn't both the static and the dynamic types of c be Base*?
When we throw an expression, the static, compile-time type of that expression determines the type of the exception object
The above is entirely true. What you forget, is that pointers are objects too. And when you throw a pointer, that's your exception object.
The object you should have dynamically1 allocated is still pointed to by that Base* pointer. And no slicing occurs on it, because there is no attempt to copy it. As such, dynamic dispatch via-pointer accesses a Derived object, and that object will use the overriding function.
This "discrepancy" is why it is usually best to construct the exception object in the throw expression itself.
1 That pointer points to a local object, you did a big no no there and got yourself a dangling pointer.
In first case you are throwing a fresh instance of Base class invoking a copy constructor because you are passing a reference to Base into throw operator.
In second case you are throwing a pointer to a stack-allocated object of type Derived that goes out of scope when exception is thrown so then you capture and then dereference a dangling pointer causing Undefined Behavior.
First scenario
I think that if you add some prints to your classes, you could see a clearer picture:
struct Base {
Base() { std::cout << "Base c'tor\n"; }
Base(const Base &) { std::cout << "Base copy c'tor\n"; }
virtual void print(std::ostream& os) { std::cout << "Base print\n"; }
};
struct Derived: public Base {
Derived() { std::cout << "Derived c'tor\n"; }
Derived(const Derived &) { std::cout << "Derived copy c'tor\n"; }
virtual void print(std::ostream& os) { std::cout << "Derived print\n"; }
};
And the output is:
Base c'tor
Derived c'tor
Derived print
throwing // Printed right before `throw b;` in main()
Base copy c'tor
Base print
As you can see, when calling throw b; there is a copy construction of a different temporary Base object for the exception. From cppreference.com:
First, copy-initializes the exception object from expression
This copy-initialization slices the object, as if you assigned Base c = b
Second scenario
First, you are throwing a pointer to a local object, causing undefined behavior, please avoid that by all means!
Let's say you fix that, and you throw a dynamically allocated pointer, it works since you are throwing a pointer, which doesn't affect the object and preserves dynamic type information.

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.

exception with non virtual destructor c++

When we go out of catch block scope, does the exception destructor get called?
(In case we don't rethrow it)
Suppose I have class A, and that its destructor is not virtual.
B inherits A.
Suppose some function threw object of B class as an exception,
and it was caught by a catch block
catch(A& a){
...
}
If the exception destructor should be called when go out of catch scope,
in this case only the base class A's destructor will be called?
Cornstalks:
live trial result in calling both class destructor.
It contradicts my logic. Explain someone?
OK, someone already answered your first question. I'll focus on this one:
if the exception destructor should be called when go out of catch scope, in this case only the base class A's d'tor will be called?
The implementation will always destroy the exception object properly regardless of how it is caught. The implementation constructs the exception object, so it knows how to destroy it. This is not the same as when you call delete through a pointer, because in that case there is incomplete information about the complete type of the object at that point (it may have been newed somewhere else) unless a virtual destructor exists.
Were this not the case, catch (...) would never work at all.
when we go out of catch block scope, does the exception destructor is called? (In case we don't rethrow it)
Yes:
[C++11: 15.1/4]: [..] The exception object is destroyed after either the last remaining active handler for the exception exits by any means other than rethrowing, or the last object of type std::exception_ptr (18.8.5) that refers to the exception object is destroyed, whichever is later. [..]
if the exception destructor should be called when go out of catch scope, in this case only the base class A's d'tor will be called?
No:
#include <iostream>
struct A
{
A() { std::cout << "A()"; }
A(const A&) { std::cout << "A(const A&)"; }
A(A&&) { std::cout << "A(A&&)"; }
~A() { std::cout << "~A()"; }
};
struct B : A
{
B() { std::cout << "B()"; }
B(const B&) { std::cout << "B(const B&)"; }
B(B&&) { std::cout << "B(B&&)"; }
~B() { std::cout << "~B()"; }
};
int main()
{
try {
throw B();
}
catch (A&) {
}
}
// Output: A()B()~B()~A()
While I'm not quoting from the standard, it seems that throwing a B and catching a A& will result in both A's and B's destructors getting called. Live demo:
#include <iostream>
struct A
{
~A() { std::cout << "A::~A" << std::endl; }
};
struct B : public A
{
~B() { std::cout << "B::~B" << std::endl; }
};
void throwit()
{
throw B{};
}
int main()
{
std::cout << "beginning main scope" << std::endl;
{
std::cout << "beginning inner scope" << std::endl;
try
{
std::cout << "calling throwit()" << std::endl;
throwit();
}
catch (A& a)
{
std::cout << "caught exception" << std::endl;
}
std::cout << "ending inner scope" << std::endl;
}
std::cout << "ending main scope" << std::endl;
}
Output:
beginning main scope
beginning inner scope
calling throwit()
caught exception
B::~B
A::~A
ending inner scope
ending main scope
As you can see, both destructors get called. The extra scope printing shows very clearly exactly when the destructors get called (at the end of the catch block).
Whenever the Standard says that an object is destroyed, it means that the correct most-derived destructor is invoked.
Always.
When you polymorphically delete an object without a virtual destructor, or you terminate (via delete operator or explicit destructor call) an object of incomplete type and the proper destructor is non-trivial, the Standard does not say that object is destroyed. It does not say that the base class destructor is invoked. It says you have undefined behavior.