1

i have been thinking, why only base class with virtual method needs virtual desctructor? look at this piece of code (read the comment):

class Base{
private:
    int x;
public:
    Base():x(0){}
    ~Base(){
        cout<<"Base dtor"<<endl;
    }
}; 

class Derived : public Base{
    int y;
public:
    Derived():y(0){}
    ~Derived(){
        cout<<"Derived dtor"<<endl;
    }
};

int main(){
    Derived *pd = new Derived;
    Base *pb = pd;
    delete pb; // this destroys only the base part, doesn't it?
               // so why doesnt the derived part leak?
    return 0;
}

I ran it with Valgrind and saw that the output was "Base dtor", and no memory leaks occurred. So, if only the base class dtor was called, why doesn't the derived class part leak?

quantdev
  • 23,517
  • 5
  • 55
  • 88
rooster
  • 665
  • 1
  • 6
  • 12
  • 3
    Because neither class is involved in allocating resources, so there's no possibility of a leak. (Nevertheless, what you're doing invokes *undefined behaviour*.) – Oliver Charlesworth Jun 05 '14 at 06:50
  • 2
    Because if you have no virtual methods, there is no reason to use a class like this. (`Base *pb = pd;`) So here, because you use the class like a polymorphic class, you need a virtual destructor! – Csq Jun 05 '14 at 06:52
  • Try again, but instead of your class `Derived` having `int y`, give it an `int * y` and make the derived constructor assign `y = new int...` and see if valgrind complains then! – druckermanly Jun 05 '14 at 06:54
  • Where did you get the premise of the question, "only base class with virtual method needs virtual dtor"? It is not true and using a virtual destructor has nothing to do with having (other) virtual methods. A better guideline is that base classes that will need to be destroyed through pointer (or reference) to the base class need virtual destructors. As others said, the example doesn't leak because you have no derived-specific allocation, so the derived destructor is a no-op. As soon as you start allocating in the `Derived` constructor, you will get a real leak. – user4815162342 Jun 05 '14 at 06:54
  • @Csq - even if he didn't have virtual methods, he could still have leak. In his example, he doesnt, but if ~Dervied was expected to free memory or release other resources, it would be a leak if he deleted an instance of Derived via a pointer to Base. – selbie Jun 05 '14 at 06:55
  • i admit i mixed here 2 questions, but the important one is about this specific code. and it may help me understand the solution to the question in the title – rooster Jun 05 '14 at 07:10

5 Answers5

2

You asked:

why doesnt the derived class part leak?

When you call

delete pb;

The runtime knows how much memory was allocated for the object and deallocates it. delete first calls an object's destructor, then deallocates the memory at the object's address. The heap manager knows how much space that is.

In this case, the object pointed to by pb is deleted, so the space for both Base::x and Derived::y is deleted.

You will experience a memory leak if Derived::~Derived() was responsible for deallocating memory.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • +1 this is factually correct (if an incomplete discussion) - not sure why it was downvoted. – Tony Delroy Jun 05 '14 at 07:08
  • thanks, i guess this really answer my question. – rooster Jun 05 '14 at 07:22
  • I also don't understand the downvote - the answer is quite correct. – user4815162342 Jun 05 '14 at 09:32
  • 1
    Also note that there is no *guarantee* that this will work as intended. One could easily imagine an optimized runtime that causes `new Base` to carve memory out of a special pool of `Base`-sized chunks, and `new Derive` to draw from a pool of `Derive`-sized chunks. Such a system would be seriously compromised by `delete pb` getting passed a pointer from the wrong pool. (Allowing such optimizations is why the standard proclaims the code undefined behavior.) – user4815162342 Jun 05 '14 at 17:07
2

The premise of the question, "only a base class with virtual methods needs a virtual destructor", is quite wrong. Using a virtual destructor has nothing to do with having (other) virtual methods in the class. A more correct guideline is to use a virtual destructor for base classes that will need to be destroyed through pointer (or reference) to the base class.

As others pointed out, your example doesn't leak because you have no derived-specific allocation, so the derived destructor is a no-op. As soon as you start allocating in the Derived constructor, you will get a real leak.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • ok, but the question is why doesnt the Derived object itself leak? i mean, there was memory allocation of size of Derived class, and only a part of this memory block was freed - the base class part. – rooster Jun 05 '14 at 07:08
  • @rooster See the second paragraph — the example doesn't leak because you don't allocate anything in the `Derived` constructor, nor deallocate anything in its destructor. If you had a deallocation there, it would be skipped, and the example would leak. – user4815162342 Jun 05 '14 at 09:34
1

It does not matter whether virtual methods are involved. It matters whether the derived classes can allocate resources. If they do, you will have a memory leak.

If Derived used new, you'd end up with a leak, regardless of methods being virtual or not.

Also as Oli says in the comment, deleting only "part of an object" results in UB, thus declaring destructor as virtual is a good practice whenever you suspect that you might need to call destructor of derived object via a pointers to base class.

Also you basically never know whether the pointer to Base points to a Base instance or Derived unless you use RTTI. This is why declaring destructors is pretty much a "go-to" approach.

luk32
  • 15,812
  • 38
  • 62
  • 1
    If derived classes can't allocate resources is it defined behavior to delete via a base class pointer when its destructor is nonvirtual? – user541686 Jun 05 '14 at 06:53
  • 1
    @Mehrdad: The standard simply says it's always UB. – Oliver Charlesworth Jun 05 '14 at 06:55
  • 1
    @OliCharlesworth: Yeah that's my point, it has nothing to do with resource allocation. – user541686 Jun 05 '14 at 06:59
  • @Mehrdad Nope. I was only talking about the leak. I edited the answer to incorporate the comments. – luk32 Jun 05 '14 at 07:01
  • "deleting only "part of an object" results in UB" - that would suggest that if `Derived` added no data members, it wouldn't be undefined behaviour, but it still is - the issue is doing a `delete` for something other than the actual runtime type (which is what `virtual` ensures in this scenario). – Tony Delroy Jun 05 '14 at 07:05
  • @TonyD I think you misunderstood "part of an object" I meant calling a destructor of the object's base class, not its own; so only the `Base` part would be cleaned up. I did not mean or mentioned any data members. Introducing data members on your own does not matter IMO and has nothing to do with it, I am not sure why you got your suggestion honestly. – luk32 Jun 05 '14 at 07:13
  • 1
    @luk32: "Part of an object" is nothing to do with it (and is thus misleading). The standard simply says that deleting an object through pointer-to-base without a virtual dtor is UB. – Oliver Charlesworth Jun 05 '14 at 07:22
  • 1
    @luk32: I understand both the C++ behaviour and what you intend by your explanation; what I'm saying to you is that talking about "part of an object" is ambiguous enough to invite misunderstanding from others. For example "only the `Base` part would be cleaned up" - someone might say "well, my `Derived` class only had a `Base` part because it didn't add data members - therefore it must be ok." <- that's invalid. "part" is too suggestive of memory layout, making it misleading. – Tony Delroy Jun 05 '14 at 07:33
  • Oh okey, I was aware of that, this is why I put it into quotation marks. My intent was to make it sound less technical and more like "simple english", technically versatile people probably do understand it already, and those who don't would get a better feeling why it doesn't make sense. – luk32 Jun 05 '14 at 08:28
0

There are two questions at hand:

  1. Why doesn't the derived class in the given example cause memory leaks?
  2. Why doesn't a base class without virtual methods need a virtual destructor?

For question #1, the answer is that you simply do not deallocate any memory in the destructor of the derived class. If you did, then the derived class in the given example would cause memory leaks.

For question #2, the answer is that if your base class does not declare any virtual methods, then there is really not much point in using it as a pointer to an instance of the derived class to begin with.


UPDATE:

You seem to be misunderstanding the term memory leaks, which can apply only on dynamically allocated memory:

  • Variables that are statically allocated (in the stack or in the data-section), are automatically deallocated at the end of the execution of their declaration-scope.

  • Variables that are dynamically allocated (in the heap), must be deallocated "manually" in order to prevent memory leaks.

barak manos
  • 29,648
  • 10
  • 62
  • 114
  • again, why doesnt the derived object itself leak? the base class destructor destroys only the base part, the member 'int y' of the object still exists – rooster Jun 05 '14 at 07:17
  • @rooster: The member `int y` is not dynamically allocated. Memory leaks can apply only on dynamically allocated memory! – barak manos Jun 05 '14 at 07:21
  • #2 is debatable - the class could have no virtual methods because its users cast it to the appropriate derived class as determined from other available context. (Often the case when C++ classes wrap C-based object systems where instances carry their own type information, such as gobject.) However, it might still be useful to be able to delete such instances through base class pointer at a place where the context and type information is unavailable, e.g. a garbage collector. – user4815162342 Jun 05 '14 at 17:04
0

why doesn't the derived class part leak? Because in Derived constructor you have not allocated memory using new try below code to see memory leakage . It is modified code of you given code:

#include <iostream> 
using namespace std; 
class Base{
private:
    int x;
public:
    Base():x(0){}
    ~Base(){
        cout<<"Base dtor"<<endl;
    }
}; 

class Derived : public Base{
    int y;
    int *a;
    public:
    //Derived():y(0){}
    Derived()
    {
        a = new int[10];
        y = 10;
        cout<<"Derived ctor";
    }

    ~Derived(){
        cout<<"Derived dtor"<<endl;
        delete a;
    }
};


int main(){
    Derived *pd = new Derived;
    Base *pb = pd;
    delete pb; // this destroys only the base part, doesn't it?
               // so why doesnt the derived part leak?
    return 0;
}

valgrind summary:

==21686== LEAK SUMMARY:
==21686==    definitely lost: 40 bytes in 1 blocks
==21686==    indirectly lost: 0 bytes in 0 blocks
==21686==      possibly lost: 0 bytes in 0 blocks
==21686==    still reachable: 0 bytes in 0 blocks
==21686==         suppressed: 0 bytes in 0 blocks
EmptyData
  • 2,386
  • 2
  • 26
  • 42