std :: map, полиморфизм и удаление - PullRequest
4 голосов
/ 22 июня 2011

У меня проблема с использованием карты C ++ для хранения указателей на базовый класс и некоторый производный класс.

Позвольте мне объяснить довольно длинный, но простой код:

#include <map>
#include <iostream>

struct foo{ int dummy[4]; };
struct bar{ int additionnal[4]; };

class Base
{
private:
    struct foo *_internal_structure;
public:
    Base() { _internal_structure = new struct foo; }
   ~Base()
   {
        delete _internal_structure;
        std::cout << "Base DTOR\n";
   }
};

class Derived: public Base
{
private:
    struct bar *_additional_structure;
public:
    Derived() { _additional_structure = new struct bar; }
   ~Derived()
   {
        delete _additional_structure;
        std::cout << "Derived DTOR\n";
   }
};


int main(int argc, char *argv[])
{
    std::map<int, Base*> my_map;
    Base *to_add = new Base();
    Derived *derived_to_add = new Derived();
    my_map[1] = to_add;
    my_map[2] = derived_to_add; // works, derived class, but object gets sliced

    /// clear hash map ///
    std::map<int, Base*>::const_iterator iter;
    for(iter = my_map.begin(); iter != my_map.end(); ++iter)
    {
        delete (*iter).second;
    }

    return 0;
}

Результатпри запуске:

Base DTOR
Base DTOR

Итак, когда я вставляю указатель класса Derived в мою карту, базовый объект рассматривается как класс Base ;поэтому вызываемый деструктор принадлежит классу Base, а не классу Derived.Valgrind подтверждает, что я каждый раз теряю 16 байт.

Кроме того, я не могу использовать Boost's shared_ptr ( Я видел некоторые упоминания об этом здесь ), ивстроенная архитектура, которую я использую, не поддерживает исключения C ++ и RTTI (что в моем случае вызывает некоторые не выровненные обращения и другие плохие вещи) ( edit : не связано).

Знаете ли вы, как я могу исправить это поведение?

Ответы [ 2 ]

13 голосов
/ 22 июня 2011

Где ваш виртуальный деструктор ??? !!!

Прочитайте это , а никогда забудьте.Действительно, вы только что нарушили одну из 10 заповедей C ++ ...:))

6 голосов
/ 22 июня 2011

Ваш деструктор в любом базовом классе должен быть виртуальным .

В противном случае во время выполнения невозможно определить, какой деструктор (ы) действительно должен быть вызван, в случае, когда на подклассы ссылаются через указатель на их базовый класс.

...