user12028520
user12028520

Reputation:

How is memory deallocated by delete operator with pointer to base class

Consider this code:

class base{
    T* obj=new T[40];
    //...
public:
    base(){/*...*/}
    virtual ~base(){
        delete[] obj;
        //...
    }
    ...
};
class derived : public base{
    T* obj2=new T[20];
    //...
public:
    derived(){/*...*/}
    ~derived(){
        delete[] obj2;
        //...
    }
    ...
};

void func(){
    base&& exmp=giveder();    //giveder() returns derived
    base* dis=new derived[50];
    //...
    delete[] dis;
}

In the above code exmp will be destructed properly as destructors are declared virtual. But my question is whether free store pointed to by dis will be deallocated as expected and if it is then how?

It is apparent that sizeof(base) and sizeof(derived) is different. But that's not gonna mess with exmp though will it mess with dis? What I think is that It will not work as there's no way to figure out the sizeof(derived) from a pointer to base and as a result it can't figure out how many bytes are needed to be freed. Although I really do want to know the language specification and whether it is legal. If that is legal, what is the workaround of freeing what is in acquisition?

A side question, arrays don't know of its own size(right?), then how are delete[] obj and delete[] obj2 in the destructors going to release memory either?

I'm new to pointer and memory management, so I'd prefer descriptive answer. Thanks

Upvotes: 5

Views: 304

Answers (2)

Daniel Langr
Daniel Langr

Reputation: 23537

As others already noticed, this:

base* dis=new derived[50];
delete[] dis;

is undefined behavior. Read, e.g, this question to understand why: Why is it undefined behavior to delete[] an array of derived objects via a base pointer?.

As a solution, I suggest to use a vector of unique pointers:

struct Base { virtual ~Base() = default; };
struct Derived : Base {
  Derived() { std::cout << "Derived constructed...\n"; }
  ~Derived() { std::cout << "Derived destroyed...\n"; }
};

int main() {
  std::vector<std::unique_ptr<Base>> v;
  std::generate_n(std::back_inserter(v), 50,
                  []{ return std::make_unique<Derived>(); });
}

Live demo: https://wandbox.org/permlink/jcG71bDb1U7wsp2T.

Of course, in this case, Derived objects will not be placed in the contiguous memory chunk.

Upvotes: 0

R Sahu
R Sahu

Reputation: 206717

Your code has undefined behavior.

It's ok to use

base* ptr = new derived();
delete ptr;

but it is not ok to use

base* ptr = new derived[10];
delete [] ptr;

Here's the relevant text from the C++11 Standard (emphasis mine):

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.

Upvotes: 7

Related Questions