user6245072 user6245072 - 1 month ago 16
C++ Question

Smart pointers and derived classes

I am going to store a large quantity of objects in a

std::list
.

Since I need those objects to store different types of data, I am storing pointers to a base class which only holds an attribute of an
enum
type which tells the objects to which of the derived classes it should be casted to. Each derived class has then its own type of data:

struct Base {
enum class Type {
D1,
D2,
...
} type;

Base(Type new_type):
type(new_type) {}
};

struct D1: public Base {
std::string data;

D1(std::string new_data):
Base(Base::Type::D1), data(new_data) {}
};

struct D2: public Base {
double data;

D2(double new_data):
Base(Base::Type::D2), data(new_data) {}
};


To hold pointers to these objects, I am using smart pointers:

std::list<std::unique_ptr<Base>> list;
list.push_back(std::unique_ptr<Base>(new D1("Somestring")));
list.push_back(std::unique_ptr<Base>(new D2(3.14)));


However, while each Base object knows what type it should be casted to to get deleted properly, the smart pointer only knows that it must call Base's destructor. Which would leave undeleted the memory each subclass allocated.

How would I pass a custom deleter to the smart pointers so that they know how to properly cast and free each object's memory? What should I implement that custom deleter?

Answer

Just mark the destructor of Base as virtual. Then the default deleter will invoke delete pointer_to_raw_object;, which will call the right destructor based on the dynamic type of object.

Example:

#include <iostream>
#include <memory>
#include <list>

struct Base
{
    virtual ~Base(){std::cout << __PRETTY_FUNCTION__ << std::endl;}
};

struct Derived : Base
{
    ~Derived() override {std::cout << __PRETTY_FUNCTION__ << std::endl;}
};

int main()
{
    std::list<std::unique_ptr<Base>> l;
    l.emplace_back(new Base);
    l.emplace_back(new Derived);
}

Live on Coliru

PS: consider using std::list::emplace_back for cleaner (and more efficient) code.