2010-11-24 13 views
10

Ich habe eine unordered_map, die den int als Schlüssel einen Zeiger als Wert speichert. Ich muss die Existenz des Schlüssels überprüfen. Wenn der Schlüssel nicht verfügbar ist, muss ich den Schlüssel und den Wert einfügen. Welcher ist der bessere Ansatz?Grundfrage beim Zuweisen von Wert zu unordered_map

Danke.

unordered_map<int, classA*>testMap; 
classA* ptr = testMap[1]; 
if(ptr == NULL) 
    testMap[1] = new classA; 


OR 

unordered_map<int, classA*>::iterator it = testMap.find(1); 
if(it == testMap.end()) 
{ 
    testMap.insert(make_pair(1, new classA)); 
} 
+0

Ich würde vorschlagen, dass Sie Ihre dynamisch erstellten 'classA'-Instanzen in einem' std :: shared_ptr' speichern: 'std :: unordered_map >'. Sie können die Instanzen mit 'std :: make_shared (... ctr params ...)' erstellen. Dies entlastet Sie von den Sorgen über Ressourcenlecks. –

+0

Der erste Ansatz oder die Variante, die das zweite Nachschlagen vermeidet, ist möglicherweise besser, wenn Sie mit Sicherheit sagen können, dass in der Map niemals gültige Nullzeiger vorhanden sind. Da Sie diese Voraussetzung jedoch nicht angegeben haben, würde ich mich für den zweiten, sicheren Ansatz entscheiden. Sie können die Funktion count() verwenden, anstatt die lokale Variable it zu finden und/oder loszuwerden, um den Code zu löschen. –

Antwort

6

Keine Methode ist gut, weil beide verwenden zwei Abfragen in der Karte, wo eine ausreichend wäre.

Ein besseres Verfahren wird eine Referenz auf das Element abrufen, und wenn das Referenz einen Nullzeiger ist, weist darauf:

classA*& ptr = testMap[1]; 
if (ptr == 0) 
    ptr = new classA; 

Dies funktioniert, weil die Abfrage ein nicht vorhandenes Elements in einer Karte automatisch einfügt (Standardkonstruiert, daher wird ein Nullzeiger eingefügt), und operator[] gibt eine Referenz an dieses Element zurück (sei es neu erstellt oder bereits vorhanden).

Beachten Sie jedoch, dass die Semantik zwischen dieser Methode (oder Ihrer ersten Methode) und Ihrer zweiten Methode sich geringfügig unterscheidet: Ihre zweite Methode fügt das Element nur ein, wenn der Schlüssel nicht in der Map vorhanden ist. Meine Methode (und Ihre erste Methode) erstellt auch ein neues Element, wenn der Schlüssel tatsächlich schon existiert hat, aber sein Wert war ein Nullzeiger.

+4

Was ist, wenn der Schlüssel bereits existiert und 'NULL' ein gültiger Wert dafür ist? – Nate

+0

Das ist im Allgemeinen keine gute Idee. Wenn Sie etwas anderes als Zeiger gespeichert haben, haben Sie möglicherweise keinen geeigneten Standardwert zum Testen. Effizienz ist hier auch kein Thema, da die Speicherzuweisung viel länger dauert als das Nachschlagen. –

+0

@Nate: siehe bearbeiten. ;-) –

0

Ich würde folgendes tun:

typedef unordered_map<int, classA*>::iterator my_iterator; 
std::pair<my_iterator, my_iterator> range = testMap.equal_range(1); 
if (range.first == range.second) //element not in map 
{ 
    testMap.insert(range.first, new classA); 
} 

EDIT: Dank für den Hinweis auf lijie, dass dies sinnlos ist. equal_range gibt zurück und [end, end] Paar, wenn der Wert für underoded_map nicht gefunden wird.

+0

Wenn das Element nicht in der 'unordered_map' ist, sind beide Iteratoren, die von' equal_range' zurückgegeben werden, 'end()'. Daher bezweifle ich, dass der Hinweis "Einfügen" nützlich ist. (d. h. es ist äquivalent zu "testMap.insert (testMap.end(), neue KlasseA)". Dies ist in jedem Fall ein Fehler; es sollte ein Paar sein). – lijie

+0

Ja, du hast recht, ich habe über eine Standardkarte nachgedacht, sorry. Ich bin mir nicht sicher, was Sie mit einem Fehler meinen, untergeordnete_map hat eine Insert-Funktion, die zwei Argumente, einen Iterator und einen Wert: http://msdn.microsoft.com/en-us/library/bb982322.aspx –

1

Die zweite ist der bessere Ansatz. In der ersten, wenn Sie classA* ptr = testMap[1] tun, erstellen Sie ein Element im Hash mit dem Standardwert NULL.

Wenn Sie den Map-Wert in einen anderen Wert als einen Zeiger ändern (z. B. vector), haben Sie möglicherweise keinen geeigneten Standardwert zum Testen. Auch in Zukunft könnte NULL ein gültiger Wert für Ihre Karte sein, daher wäre Ihr Standardwerttest bedeutungslos.

+2

Warum der Downvote? –

+0

Ich habe nicht downvote, aber ich würde den zweiten Ansatz mit einem anderen Grund sagen: Sie erstellen nie Einträge, die ungültig sind. –

0

In Bezug auf Effizienz glaube ich, dass sie gleichwertig sind.

Im ersten Fall, wenn der Eintrag nicht bereits vorhanden ist dann der Aufruf an:

classA* ptr = testMap[1]; 

wird ein leeres Element in der Karte tatsächlich erstellen, die Sie dann in der if-Anweisung füllen würden.

Der zweite Eintrag fügt nur einen Eintrag zur Karte hinzu, wenn Sie insert anrufen.

Also ich denke, es kommt darauf an, welcher Stil Ihnen besser passt!

Verwandte Themen