2013-07-25 9 views
8

Ich verwende std::map, um Zeichenfolgenwerte auf MyType * zu mappen. Meine Karte Deklaration sieht wie folgt aus:Ordnungsgemäße Methode zum Zerstören einer Karte mit Zeigerwerten

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

my_map eine Variable von einer meiner Klassen Privat Mitglied ist. Mein Problem ist, dass ich mir nicht sicher bin, wie ich die Karte zerstören soll. Wenn ich die Karte lösche, möchte ich auch delete auf allen in der Karte enthaltenen MyType * aufrufen. Hier ist mein aktueller destructor:

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

Wird dies die Zeiger löscht in der Karte enthalten ist, oder muß ich durch die Karte iterieren jeden Zeiger löschen vor dem Aufruf löschen?

+2

Die später - 'map' (und die meisten (wenn nicht alle) Container in der Standardbibliothek?) Wurde entwickelt nicht jeder Zeiger enthält auf Zerstörung zu löschen. – Nbr44

+0

Ok danke. Die Dokumentation, die ich gelesen habe, war nicht sehr klar. Es lautete: 'Dies reduziert die Containergröße effektiv um die Anzahl der entfernten Elemente, die zerstört werden. – Max

+3

Das ist ein häufiges Missverständnis - die Zeiger selbst werden zwar zerstört, aber das ändert nicht den Zustand des Speicherorts, auf den sie zeigen . – Nbr44

Antwort

9

Zeiger zeigen lediglich. Wenn Sie rohe Zeiger verwenden, müssen Sie wissen, welcher Teil Ihrer App die Ressourcen besitzt, auf die die Zeiger zeigen. Wenn sie der Karte gehören, müssen Sie über die Karte iterieren und für jeden Zeiger delete aufrufen, bevor die Karte zerstört wird. Wenn die Karte jedoch nur Zeiger auf Objekte enthält, die anderen Teilen Ihres Codes gehören, müssen Sie nichts tun.

Eine sicherere Lösung besteht darin, shared_ptr zum Verwalten der Objektlebensdauer zu verwenden, wodurch sichergestellt wird, dass das Objekt ordnungsgemäß gelöscht wird, wenn das letzte shared_ptr zerstört wird. Sie können shared_ptrs innerhalb der Map speichern, und wenn keine anderen shared_ptr-Instanzen auf die Objekte innerhalb der Map verweisen, werden die Objekte bei Bedarf zerstört, wenn die Map zerstört wird.

2

Wenn Sie smart pointers anstelle von rohen Zeigern verwenden, wird alles automatisch für Sie aufgeräumt.

// 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

Wird dies die in der Karte [...] enthaltenen Zeiger löschen?

Nein, angesichts des von Ihnen bereitgestellten Codes werden Sie jedes Mitglied der Karte verlieren.

In der Regel muss für jede new ein passender delete vorhanden sein. Sie haben eine delete für die Karte, aber keine für die Elemente innerhalb.

Die korrekteste Lösung für dieses Problem ist, keine dynamische Zuordnung zu verwenden. Nur speichern MyType s Verzeichnis, wenn möglich:

map<string, MyType>

... und statt dynamisch die map Zuweisung selbst, zu speichern, die automatisch:

map<string,MyType> my_map; 

Wenn die automatische Speicherdauer für einige nicht möglich ist, Grund, dann verwenden Sie einen intelligenten Zeiger für die dynamischen Zuordnungen. Bei einem Compiler 11 C++, verwendet unique_ptr (oder selten oder gar shared_ptrweak_ptr) für die Elemente in den map: (. Bei einem gegebenen C++ Kompilierer 03, verwenden, um den Boost-Äquivalente davon)

map<string, unique_ptr<MyType>> my_map; 

Wenn dann my_map zerstört wird, werden alle Elemente delete d.

Baring dies alles, wenn Sie in einer Situation sind, wo keiner der oben für Sie arbeiten (ich würde durch höchst verdächtig), dann müssen Sie die Karte youself iterieren:

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

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

In C 11 ++, könnte dies eine Lambda, etwas entlang der Linie gemacht werden:

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

In der modernen C++, nur das Leben leichter machen und die Nutzung Zeiger nur wenn unbedingt erforderlich.

Sie haben mit diesem Code:

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

Das erste, was Sie tun können, mit einem std::map Beispiel als Datenelement anstelle eines Zeiger, um es zu prüfen ist.

Wenn dann MyType nicht super-teuer zu kopieren und seine Instanzen werden nur von der Karte gehört, man denke nur eine einfache map von string zu MyType (statt MyType*):

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

Wenn Sie wirklich braucht eine Karte enthält, Zeiger, betrachtet mit intelligenten Zeigern, wie std::shared_ptr (erhältlich in C++ 14.11) für die gemeinsamen Besitz oder std::unique_ptr für einzigartigen nicht geteilten Besitz.
(Wenn Sie C++ 98/03 Ziel, ist eine Option boost::shared_ptr zu verwenden, da es keine Bewegung Semantik ist, kann man nicht unique_ptr haben können, die verfügen über Semantik in Bewegung stark basiert..)
zB:

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

Wie Sie sehen können, mit Wert Semantik (anstelle von rohen Zeiger) oder intelligente Zeiger, können Sie Ihren Code und verwenden Sie die automatische Zerstörung zur Verfügung gestellt von C++ vereinfachen.

Verwandte Themen