2010-12-29 9 views
13

mam map jak toCzy bezpiecznie jest uzyskać obiekt w std :: map przez odniesienie?

map<int,object> objmap; 
object& obj = objmap.find(num)->second; 
object& obj2 = objmap[num]; 

Jakiekolwiek zmiany wprowadzone w obiekcie muszą być widoczne na mapie. Podobnie nie można zrobić w wektorze, ponieważ zmienia położenie obiektów, gdy chce więcej miejsca. Czy można to bezpiecznie zrobić na std :: map? i czy jest to wskazane? Druga wersja zawiera błąd, ponieważ mój obiekt nie ma pustego konstruktora. Jeśli zadeklaruję pustego konstruktora, który nic nie robi, czy dwie linie będą działały w ten sam sposób?

Odpowiedz

18

Dopóki przedmiot nie zostanie usunięty z mapy, oznacza to, że jest bezpieczny. Po wstawieniu do obiektów mapy nie poruszaj się, nawet jeśli inne elementy są dodawane lub usuwane.

object& obj = objmap.find(num)->second; 

Jest to potencjalnie niebezpieczne, chyba że jesteś pewien, że element z kluczem num rzeczywiście istnieje na mapie. Jeśli nie masz pewności, możesz użyć przeciążenia insert, które zwraca wartość iterator i bool, która wskazuje, czy wstawiono nowy element, czy element z danym kluczem był już obecny na mapie.

E.g.

object& obj = objmap.insert(std::make_pair(num, object(arg1, arg2, argN))).first->second; 
+1

Czy wiesz, gdzie i jak znaleźć takie informacje w dokumentacji? Właściwie to nawet nie wiedziałem, jak szukać tej odpowiedzi: jaki jest właściwy sposób mówienia "obiekty nie poruszają się"? Domyślam się, że specyfikacja musi to precyzyjnie zdefiniować, ponieważ jest to tak ważna różnica między wektorem a mapą. – Flynsee

11

Jest to bezpieczne, o ile element nie zostanie usunięty z mapy.

jednak druga linia nie jest dość bezpieczne:

object& obj = objmap.find(num)->second; 

Jeśli nie ma elementy o kluczowym num na mapie, find powróci objmap.end(). Możliwość ta powinna być testowana przed dereferencji zwrócony iterator:

const std::map<int, object>::iterator it = objmap.find(num); 
if (it != objmap.end()) 
{ 
    object& obj = it->second; 
    /* ... */ 
} 

Teraz, jeśli celem jest naprawdę nie do znaleźć ale naprawdę wstawić, nazywając operator[] możliwość (chociaż, jak już zauważyliśmy, to wymaga wartości do zapewnienia konstruktora bez parametrów). Ale trzeba zrozumieć, że są to dwie zupełnie różne rzeczy:

  • findtylko stwierdza: jeśli klucz nie zostanie znaleziony, nic nie zostanie włożona i end iterator wraca
  • operator[]zawsze zwrotów odniesienie do wartości na mapie: jeśli nie ma klucza, następuje wstawienie (dla domyślnej skonstruowanej wartości: w związku z tym wymaganie konstruktora)
1

Jeśli chcesz wprowadzić zmiany w obiekt na mapie do odzwierciedlenia, prawdopodobnie będziesz chciał zmienić mapę, aby przechowywać wskaźniki do obiektów zamiast samych obiektów. Odwołania mogą działać tak długo, dopóki nie wykonasz żadnych czynności dla obiektu pomiędzy odwołaniem, które je unieważnia.

Na przykład, następujący kod złamie pomocą odwołań:

object& obj = objmap.find(num)->second; 
objmap.erase(objmap.find(num)); // should check for objmap.end() - left out for simplicity 
obj.DoSomething(); // this object has been destroyed, so the reference is invalid 
4

Jeśli pytanie brzmi, czy std::map unieważnia jego iteratory w jego funkcji mutowania to odpowiedź jest negatywna. Standard gwarantuje, że std::map nie unieważnia jego iteratorów.

0

Wykonanie tego, co robisz, jest częstym sposobem wdrożenia buforowania.

Jeśli przedmiot już tam jest, operator [] zwraca przedmiot. Jeśli go tam nie ma, utworzy "puste" z domyślnym konstruktorem i możesz do niego napisać do późniejszego wykorzystania.

Oczywiście powszechnie używa się shared_ptr jako value_type, który po utworzeniu będzie miał "pustą" wartość. W takim przypadku musisz pobrać shared_ptr przez referencję, aby można było wywołać reset() na nim.

Podobnie jak w przypadku wszelkich kolekcji/buforowania itp., Należy uważać na problemy z bezpieczeństwem wątków, jeśli odbywa się to w aplikacji wielowątkowej.

Nie jestem pewien, czy chciał (a) Pan (i) wiedzieć, czy można gdzieś umieścić odniesienie (lub wskaźnik do niego) i oczekiwać, że będzie on ważny później, gdy do mapy zostaną dodane inne elementy, i tak, będzie .

Powiązane problemy