Hi Guys,
Can someone please explain me why this is happening

#include<iostream>
using namespace std;

class a {

public:
int a1;     // If I remove this it'll work fine
a() {
       cout << "Constructor of a \n";
    }
~a() {
         cout << "Destructor of a \n";
    }

};

class b : public a{

public:
b() {
 cout << "constructor of b \n";
}
virtual ~b() {    // If I remove virtual from here ... it'll work fine
 cout << "destructor of b\n";
}

};

int main() {
 a *p = new b;

 delete p;

 return 0;
}

Result is :
Constructor of a
constructor of b
Destructor of a
a.out(1563) malloc: *** error for object 0x100154: Non-aligned pointer
being freed
*** set a breakpoint in malloc_error_break to debug
----------------------------------------------------------------

I know that if I'll put virtual in front of the destructor of the base class code will work fine. But, I want to use it the above way. Can someone please explain me the reason behind this kind of behavior?

Thanks in advance

Virtual functions are resolved during run-time. I'm guessing that it's a compilation error due to the difference in your base class destructor and derived class (the derived class being virtual and the base class not). If you add virtual to the base class destructor you'll see it compiles fine and encounters no error. Likewise if you remove virtual from the derived class, it compiles fine (although without virtual, the you will not achieve the desired results)

Virtual functions are resolved during run-time. I'm guessing that it's a compilation error due to the difference in your base class destructor and derived class (the derived class being virtual and the base class not). If you add virtual to the base class destructor you'll see it compiles fine and encounters no error. Likewise if you remove virtual from the derived class, it compiles fine (although without virtual, the you will not achieve the desired results)

Thanks for your reply but as I have mentioned I know that if I am adding virtual in base class destructor it is working fine but I want to know why is that failing in the code I am using. And in my code if I remove the int data member from the base class it works fine. I am not getting it why it is doing that

When I removed the data member a1, I still received the same error in MSVC9.

Also to note, destructors are called in reverse order of inheritance. Virtual destructors ensure that they are called in order. If you don't declare it as virtual, the derived class destructor is not called and memory leaks ensue. That's probably why you're receiving that error.

When I removed the data member a1, I still received the same error in MSVC9.

Also to note, destructors are called in reverse order of inheritance. Virtual destructors ensure that they are called in order. If you don't declare it as virtual, the derived class destructor is not called and memory leaks ensue. That's probably why you're receiving that error.

I am using gcc UNIX compiler and it works fine when I remove that int from the base class

#include<iostream>
using namespace std;

class a {

public:
//int a1; // If I remove this it'll work fine
a() {
cout << "Constructor of a \n";
}
~a() {
cout << "Destructor of a \n";
}

};

class b : public a{

public:
b() {
cout << "constructor of b \n";
}
virtual ~b() { // If I remove virtual from here ... it'll work fine
cout << "destructor of b\n";
}

};

int main() {
a *p = new b;

delete p;

return 0;
}

:!./a.out
Constructor of a
constructor of b
Destructor of a

Press ENTER or type command to continue

Although it may be compiling correctly, the destructor is never called for your inherited class. Note the output on the screen and the absence of the b class destructor. Somehow removal of the data member doesn't trigger the memory leak warning, although it is still there. Compiling it within another compiler would certainly show it as a warning or a run-time error (such as in my case).

Edit: tired and filling in the missing words

in the original code, the layout of classes a and b are as follows (addresses increasing from the bottom of the page to the top):

layout of object of class A

            _____________________
            |                   |
            |                   |
            |   int a1          |
            |                   |
A* -------->---------------------


layout of object of class B

            _____________________
            |                   |
            |   anonymous       |
            |   subobject a     |
            |                   |
A* -------->---------------------
            |                   |
            |   vtbl pointer    |
            | points to b::vtbl |
            |                   |
B* -------->---------------------

note: with this layout
conversion from a B* to an A* is expensive (check for NULL, if not NULL add an offset which is a constant known at compile time)
vtbl lookup is fast (a B* is itself the vtbl pointer, addition of an offset is not needed).
this is a typical optimization applied by C++ compilers

this can be verified by printing out the two pointers. and the error is obvious.

#include<iostream>
using namespace std;

class a {

public:
int a1; // If I remove this it'll work fine
a() {
cout << "Constructor of a \n";
}
~a() {
cout << "Destructor of a \n";
}

};

class b : public a{

public:
b() {
cout << "constructor of b \n";
}
virtual ~b() { // If I remove virtual from here ... it'll work fine
cout << "destructor of b\n";
}

};

int main()
{
  b* pb = new b ; // memory allocated at address pb
  cout << "b* pb: " << pb << '\n' ;
  a *p = pb ;
  cout << "a* p: " << p << '\n' ;
  delete p; // destructor of a is called
     // tries to release memory at address p
     // resulting in the debug warning/error
     // a. p does not meet the alignment requirements for
     //    dynamically allocated memory (typically 8)
     // b. p is *not* the pointer returned by the allocation 
}

if the only member of A is removed, the layout is subject to "empty base class optimization" as mandated by the standard.

if there are no virtual functions in B, the optimization of the layout is not applied; A* and B* point to the same address.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.