2011-11-23 6 views
20

W jaki sposób można uzyskać dostęp do elementów unique_ptr kontenera (przez iterator) bez odrywania własności od kontenera? Kiedy dostaje się iterator do elementu w kontenerze, czy własność elementu nadal znajduje się w kontenerze? Co powiesz na pytanie, kiedy dereferencje z iteratora są usuwane, aby uzyskać dostęp do unique_ptr? Czy to wykonuje niejawny ruch unique_ptr?Powtórzenie kontenera unique_ptr's

Uważam, że używam shared_ptr, gdy potrzebuję przechowywać elementy w kontenerze (nie według wartości), nawet jeśli kontener pojęciowo posiada elementy, a inny kod po prostu chce manipulować elementami w kontenerze, ponieważ "boję się, że nie będę mógł uzyskać dostępu do elementów unique_ptr w kontenerze, bez odebrania z niego prawa własności.

Jakieś spostrzeżenia?

Odpowiedz

13

Dopóki nie będziesz próbował wykonać kopii urządzenia unique_ptr, możesz go po prostu użyć. Będziesz musiał "podwójnie dereferencji" iteratora, aby uzyskać wartość wskaźnika, tak jak trzeba z shared_ptr. Oto krótki przykład:

#include <vector> 
#include <memory> 
#include <iostream> 

template <class C> 
void 
display(const C& c) 
{ 
    std::cout << '{'; 
    if (!c.empty()) 
     std::cout << *c.front(); 
    for (auto i = std::next(c.begin()); i != c.end(); ++i) 
     std::cout << ", " << **i; 
    std::cout << "}\n"; 
} 

int main() 
{ 
    typedef std::unique_ptr<int> Ptr; 
    std::vector<Ptr> v; 
    for (int i = 1; i <= 5; ++i) 
     v.push_back(Ptr(new int(i))); 
    display(v); 
    for (auto i = v.begin(); i != v.end(); ++i) 
     **i += 2; 
    display(v); 
} 

Jeśli tak (przypadkowo) zrobić kopię unique_ptr:

Ptr p = v[0]; 

wtedy dowiesz się w czasie kompilacji. Nie spowoduje to błędu czasu wykonywania. Twój przypadek użycia jest powodem, dla którego zbudowano container<unique_ptr<T>>. Rzeczy powinny po prostu działać, a jeśli nie, problem pojawia się w czasie kompilacji, a nie w czasie wykonywania. Odłóż kod, a jeśli nie rozumiesz błędu czasu kompilacji, zadaj tu jeszcze jedno pytanie.

+0

Okej, myślę, że to wyjaśnia dla mnie. Miałem zwyczaj używania nowej funkcji for_each z lambdą, której parametrem jest element przekazywany przez wartość, a nie przez odniesienie, ale myślę, że będę musiał utworzyć odniesienie dla elementów unique_ptr, jeśli chcę uniknąć próby kopiuj/przenieś. P.S. jeśli raz zrezygnuję z iteratora i odniesiemy się do tego wyniku, zakładam, że to pomija próbę skopiowania? Mam na myśli: 'for (Container :: iterator it = container.begin(); it! = Container.end(); it ++) { unique_ptr & element = &*it; // Nie próbowano skopiować? } ' Dzięki Howard, przy okazji. –

+0

Tak, myślę, że to powinno działać dobrze. Chociaż masz dodatkowe '&' w swoim kodzie. Ale kompilator powie ci, gdzie. –

+0

Powinieneś być w stanie dereferencji do: blah & element = ** it; wciąż bez kopii, myślę. (Prawdopodobnie bardziej przydatne.) –

32

Z auto a zakres oparte na pętli-C++ 11 staje się stosunkowo elegancki:

std::vector< std::unique_ptr<YourClass>> pointers; 
for(auto&& pointer : pointers) { 
    pointer->functionOfYourClass(); 
} 

Odniesienie & do std::unique_ptr zapobiega kopiowaniu i można użyć uniqe_ptr bez dereferencji.

+0

Czy ktoś wie, czy istnieje różnica między używaniem 'auto &' i 'auto &&' w tym przypadku? To odniesienie sugeruje podwójne i http://pl.cppreference.com/w/cpp/language/range-for, oba wydają się kompilować – austinmarton

+0

Dobre pytanie. Znalazłem [ten link] (http://en.cppreference.com/w/cpp/language/auto) (patrz Wyjaśnienie/1), co sugeruje, że 'auto &&' może działać jako l-wartość i r-wartość w zależności od inicjalizatora. Odpowiednio dostosowuję przykład. – Pascal