Nav
Nav

Reputation: 20658

Base class's destructor called without destroying the base class!

#include<iostream>
using namespace std;

class A
{
public:
        int i;
        A() {cout<<"A()"<<endl;}
        ~A() {cout<<"~A()"<<endl;}
};
class B:public A
{
public:
        int j;
        B(): j(10)
        {
                this->i=20;
                this->~A();
        }
};

int main()
{
        B abc;
        cout<<"i="<<abc.i<<" j="<<abc.j<<endl;
}//main

Two questions:

  1. How come A's destructor gets called like an ordinary function instead of destroying the object? (or is it some kind of rule that the base class will be destroyed only if the child class's destructor calls the base class's destructor?) I was trying out this sample code to find out how the destructor works. So if simply calling the destructor function does not destruct the object, then there is obviously some other kind of call that calls the destructor and only then the object is destructed. What's so special in that kind of call and what call is it?
  2. Is there a way to have an initialization list for A in B's constructor? Something like this:

    class B:public A
    { 
        B(): j(10), A():i(20) {}
    };
    

Upvotes: 1

Views: 1032

Answers (7)

Stack Overflow is garbage
Stack Overflow is garbage

Reputation: 247999

@Nav: no, your understanding of "destroyed" is just wrong. When an object's destructor is called, the object is destroyed. You seem to believe that the memory it resided in evaporates entirely, but that never happens. The object no longer exists, but some garbage data is typically left over by the object, and if you're willing to break the rules of C++ and invoke undefined behavior, then you can read those leftover bytes, and they'll look like the object, and because there are no runtime checks on whether you're accessing a valid object, you can often treat them as an object. Which you do.

It's illegal, it's undefined behavior, but in practice it often works.

Once again, a destructor does not physically vaporize the memory. Your RAM still has the same capacity after a destructor has executed. Conceptually, the object no longer exists once the destructor has run. But the data it contained is still there in memory.

Upvotes: 4

Jan
Jan

Reputation: 1847

If you call ~SomeClass() yourself, explicitly, the destructor function will be called. Which leaves the object (in this case, the base class part of the object) in a destroyed state.

Since the destructor is not virtual, the destructor of derived classes will not be called, but base classes of SomeClass will be destroyed too.

Trying to find out if A is really destroyed by just using the i member, is not a good test. In fact, you can't test this, since using the object results in undefined behavour. It may work, or it may not (in your case, it probably will print "i=20 j=10", but i is already destroyed).

Upvotes: 2

ipapadop
ipapadop

Reputation: 1472

In the code that you are giving, you are indeed destroying the base class and as such i. Calling a destructor and then using the dead object is undefined behavior - it may work or it may crash.

Should i was something that is more complex that an int (for example a vector), trying to do anything with that would probably result in a crash.

Upvotes: 2

Buhake Sindi
Buhake Sindi

Reputation: 89169

For point:

  1. This is an undefined behaviour but only ~A() is called though an instance of class B because ~A() is not declared virtual. See more on Wikipedia.
  2. No. For derived classes, first call your parent class, then assign parameters.

For point 1) on Wikipedia:

having no virtual destructor, while deleting an instance of class B will correctly call destructors for both B and A if the object is deleted as an instance of B, an instance of B deleted via a pointer to its base class A will produce undefined behaviour.

Example (for point 2):

B(): A(), j(10) {}

or

B(): A() {j = 10;}

Upvotes: 3

Kiril Kirov
Kiril Kirov

Reputation: 38173

  1. The base class's destructor should be virtual. Here, as it's created on the stack, it's not problem, but anyway..
  2. No, but you can call the class A() constructor in the initialize list of B's constructor, like this:
    B(): A( .. ), ...

A* a = new B();
//..
delete a;

will not call B's destructor unless class A destructor is virtual. That's why STL containers should not be derived - theirs destructors are not virtual.

Upvotes: 5

Naveen
Naveen

Reputation: 73443

  1. Destructor is like any other normal function which you can call (but you should never do it unless you use a placement new). When you call delete on a object two things happen: Destructor is called for cleanup and then operator delete is called to release the memory allocated for the object. Here the second step is not happening.

  2. No, you can not call it like that. What you can do is some thing like this:

    class A { public: A(int n) : i(n){} };

    class B : public A { public: B() : A(20), j(10){} };

Upvotes: 5

user001
user001

Reputation: 444

1) Destructor calling order in C++ is reverse order of the constructor calling order. So first derived class object get destroy and then base class object.

2) No.

Upvotes: 2

Related Questions