2016-11-02 3 views
1

Я собираюсь хранить большое количество объектов в std::list.Умные указатели и производные классы

Поскольку мне нужны эти объекты для хранения различных типов данных, я сохраняю указатели на базовый класс, который содержит только атрибут типа enum, который сообщает объектам, к какому из производных классов он должен быть добавлен. Каждый производный класс имеет то свой собственный тип данных:

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) {} 
}; 

Чтобы держать указатели на эти объекты, я использую смарт-указатели:

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))); 

Однако, в то время как каждый базовый объект знает, какого типа он должен быть чтобы удалить его правильно, умный указатель знает, что он должен вызвать деструктор базы. Который оставил бы undeleted память каждого выделенного подкласса.

Как передать пользовательский удаляющий элемент интеллектуальным указателям, чтобы они знали, как правильно снимать и освобождать память каждого объекта? Что мне следует реализовать в этом пользовательском делете?

+0

Как насчет 'virtual' destructor в' Base' вместо пользовательского удаления? –

ответ

6

Просто отметьте деструктор Base как virtual. Затем дефолт по умолчанию будет вызывать delete pointer_to_raw_object;, что вызовет правильный деструктор на основе динамического типа object.

Пример:

#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: рассмотреть вопрос об использовании std::list::emplace_back для более чистой (и более эффективной) коды.

Смежные вопросы