Ist es sinnvoll, einen Zeiger zu verwenden, um auf Werte in einer std :: map zuzugreifen?

9

Ist es gefährlich, einen Zeiger aus einem std::map::find an die Daten zurückzugeben und diesen im Gegensatz zu einer Kopie der Daten zu verwenden?

Momentan erhalte ich einen Zeiger auf einen Eintrag in meiner Map und gebe ihn an eine andere Funktion weiter, um die Daten anzuzeigen. Ich mache mir Sorgen über das Verschieben von Objekten, wodurch der Zeiger ungültig wird. Ist das ein echtes Problem?

Hier ist meine Beispielfunktion:

%Vor%

}

    
Jason 08.05.2013, 14:03
quelle

4 Antworten

7

Es wäre zweifellos typischer, einen Iterator als einen Zeiger zurückzugeben, obwohl es wahrscheinlich wenig Unterschied macht.

Soweit gültig bleibt: Ein Map-Iterator bleibt solange gültig, bis das Element, auf das es verweist, aus der Map entfernt / gelöscht wird.

Wenn Sie einen anderen -Knoten in die Karte einfügen oder löschen, kann dies dazu führen, dass die Knoten in der Karte neu angeordnet werden. Das geschieht, indem man die Zeiger zwischen den Knoten manipuliert, also ändert er, welche anderen Knoten Zeiger auf den Knoten haben, den Sie interessieren, ändert aber nicht die Adresse oder den Inhalt dieses bestimmten Knotens, so dass Zeiger / Iteratoren für diesen Knoten gültig bleiben / p>     

Jerry Coffin 08.05.2013 14:09
quelle
2

Solange Sie, Ihr Code und Ihr Entwicklungsteam die Lebensdauer der std :: map-Werte verstehen (gültig nach insert und ungültig nach erase , clear , assign oder operator= ), dann ist die Verwendung von iterator , const_iterator , ::mapped_type* oder ::mapped_type const* gültig. Wenn die Rückgabe immer garantiert ist, ist auch ::mapped_type& oder ::mapped_type const& gültig.

Ich würde die const -Versionen den mutierbaren Versionen vorziehen, und ich würde Referenzen über Zeigern den Iteratoren vorziehen.

Die Rückgabe eines Iterators gegenüber einem Zeiger ist schlecht:

  • es macht ein Implementierungsdetail verfügbar.
  • es ist umständlich zu verwenden, da der Aufrufer wissen muss, um den Iterator zu dereferenzieren, dass das Ergebnis ein std :: -Paar ist, und dass man dann .second aufrufen muss, um den tatsächlichen Wert zu erhalten.
    • .first ist der Schlüssel, der dem Benutzer nicht wichtig ist.
  • um zu bestimmen, ob ein Iterator ungültig ist, erfordert die Kenntnis von ::end() , die dem Aufrufer offensichtlich nicht zur Verfügung steht.
Charles L Wilcox 08.05.2013 14:19
quelle
1

Es ist nicht gefährlich - der Zeiger bleibt so lange gültig wie ein Iterator oder eine Referenz.

In Ihrem speziellen Fall würde ich jedoch argumentieren, dass es sowieso nicht das Richtige ist. Ihre Funktion gibt bedingungslos ein Ergebnis zurück. Es gibt nie null zurück. Warum also nicht eine Referenz zurückgeben?

Auch einige Kommentare zu Ihrem Code.

%Vor%

Warum kombinieren Sie Deklaration und Zuweisung nicht in Initialisierung? Wenn Sie C ++ 11-Unterstützung haben, können Sie einfach

schreiben %Vor%

Dann:

%Vor%

Sie können das Einfügen mit make_pair vereinfachen. Sie können auch die redundante Suche vermeiden, da insert ein Iterator für das neu eingefügte Element (als erstes Element eines Paares) zurückgibt.

%Vor%

Schließlich:

%Vor%

Benutze niemals C-Style-Modelle. Es könnte nicht das tun, was Sie erwarten. Benutze auch keine Würfe, wenn sie nicht notwendig sind. & amp; foundStruct- & gt; second hat bereits den Typ MyStruct *, also warum einen Cast einfügen? Die einzige Sache, die es tut, ist, einen Platz zu verstecken, den Sie ändern müssen, wenn Sie jemals den Werttyp Ihrer Karte ändern.

    
Sebastian Redl 08.05.2013 14:30
quelle
0

Ja,

Wenn Sie eine generische Funktion erstellen, ohne deren Verwendung zu kennen, kann es gefährlich sein, den Zeiger (oder den Iterator) zurückzugeben, da dieser ungültig werden kann.

Ich würde einen von zweien empfehlen:
1. arbeite mit std :: shared_ptr und gib das zurück. (siehe unten)
2. Rückgabe der Struktur nach Wert (kann langsamer sein)

%Vor%     
Roee Gavirel 08.05.2013 14:41
quelle

Tags und Links