2013-07-25 3 views
8

Я использую std::map для отображения значений строк до MyType *. Моя карта заявление выглядит следующим образом:Правильный способ уничтожить карту со значениями указателя

map<string, MyType *> *my_map = new map<string, MyType>; 

my_map является частным переменным членом одного из моих классов. Моя проблема в том, что я не уверен, как разрушить карту. При удалении карты я также хотел бы позвонить delete по всем MyType *, содержащимся на карте. Вот мой текущий деструктор:

my_map->erase(my_map->begin(), my_map->end()); 
delete my_map; 

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

+2

Более поздние - контейнеры 'map' (и большинство (если не все?) В стандартной библиотеке) не были предназначены для удаления любого указателя, который он содержит при уничтожении. – Nbr44

+0

Хорошо спасибо. Документация, которую я прочитал, была не совсем понятна. Он гласит: «Это эффективно уменьшает размер контейнера по количеству удаленных элементов, которые уничтожаются». – Max

+3

Это распространенное недоразумение - сами _pointers_ действительно уничтожены, но это не изменяет состояние места памяти, на которое они указывают , – Nbr44

ответ

9

Указатели просто указывают. При использовании исходных указателей вы должны знать, какая часть вашего приложения владеет ресурсами, на которые указывают указатели. Если они принадлежат карте, вам нужно будет перебирать карту и вызывать удаление на каждом указателе до того, как карта будет уничтожена. Но если карта просто содержит указатели на объекты, принадлежащие другим частям вашего кода, вам не нужно ничего делать.

Более безопасное решение - использовать shared_ptr для управления временем жизни объекта, что гарантирует, что объект будет удален должным образом при уничтожении последнего shared_ptr. Вы можете хранить shared_ptrs внутри карты, и если никакие другие экземпляры shared_ptr не ссылаются на объекты внутри карты, объекты будут уничтожены, когда карта будет уничтожена, если это необходимо.

2

Если вы используете smart pointers вместо необработанных указателей, все будет автоматически очищено для вас.

// header: 
using MapType = std::map<std::string, std::shared_ptr<MyType>>; 
shared_ptr<MapType> my_map; 

// usage: 
my_map.emplace("foo", std::make_shared<MyType>()); 

// destructor: 
MyClass::~MyClass() 
{ 
    // nothing! 
} 
3

Будет ли это удалить указатели, содержащиеся в карте [...]?

Нет, с учетом кода, который вы предоставили, вы будете утечка каждого члена карты.

Как правило, для каждого new должно быть соответствующее delete. У вас есть delete для карты, но нет элементов для внутри.

Наиболее правильное решение этой проблемы - не использовать динамическое распределение вообще. Просто хранить MyType сек каталог, если это возможно:

map<string, MyType>

... и вместо динамического выделения самого map, магазин, который автоматически:

map<string,MyType> my_map; 

Если автоматический срок хранения не представляется возможным для некоторых разум, затем используйте интеллектуальный указатель для динамических распределений. Учитывая, C++, 11 Компилятор а, использовать unique_ptr (или, реже, shared_ptr или даже weak_ptr) для элементов в map: (. Учитывая компилятор C++ 03, используют их эквиваленты подпиточного)

map<string, unique_ptr<MyType>> my_map; 

Затем, когда уничтожается my_map, все элементы будут delete d.

Baring все это, если вы находитесь в ситуации, когда ни один из вышеперечисленных не будет работать для вас (я бы высоко подозреваемого), то вам нужно будет перебирать карту ОТСИДЕТЬ:

struct deleter 
{ 
    template <typename T> operator() (const T& rhs) const 
    { 
    delete rhs.second; 
    } 
}; 

for_each (my_map->begin(), my_map->end(), deleter()); 

В C++ 11, это может быть сделано лямбда, что-то вдоль линии:

for_each (my_map->begin(), my_map->end(), [](auto item) -> void 
{ 
    delete item.second; 
}); 
1

в современном C++, просто сделать вашу жизнь проще и использовать указатели только если строго необходимо.

Вы начали с этим кодом:

map<string, MyType *> *my_map = new map<string, MyType>; 

Первым, что вы можете сделать, это рассмотреть вопрос об использовании std::map экземпляра в качестве элемента данных, вместо указателя к нему.

Тогда, если MyType не супер-дорогой, чтобы скопировать и его экземпляры только принадлежат карте, просто рассмотрим простой map от string к MyType (вместо MyType*):

// my_map data member - no pointers --> automatically deleted in class destructor 
map<string, MyType> my_map; 

Если вы действительно нужна карта, содержащая указатели, рассмотрите использование умных указателей, например std::shared_ptr (доступно на C++ 11/14) для совместного использования, или std::unique_ptr для уникального не общего доступа.
(Если цель C++ 98/03, вариант заключается в использовании boost::shared_ptr Поскольку нет перемещения семантики, вы не можете иметь unique_ptr, которая в значительной степени основана на ходу отличать семантику.).
например:

// Map containing _smart_ pointers 
//  --> default destructor is fine (no need for custom delete code) 
map<string, shared_ptr<MyType>> my_map; 

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

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