2013-01-23 17 views
9

Chcę mieć wektor wskaźników do obiektów w mojej klasie. Aby uniknąć tworzenia dla niego destruktora, chciałem użyć std::unique_ptr, ponieważ obiekty są tworzone/posiadane/niszczone w mojej klasie, ale mam błąd kompilatora, którego nie mogę zrozumieć. Następny kod będzie służyć jako krótki próbki do mojego problemu:Jakie jest prawidłowe użycie std :: unique_ptr podczas przesuwania do std :: vector

std::unique_ptr<int> createPtr(int value) 
{ 
    std::unique_ptr<int> ptr(new int(value)); 
    return ptr; 
}; 

int main() 
{ 
    std::vector<std::unique_ptr<int>> vec; 
    vec.push_back(createPtr(1)); 

    std::unique_ptr<int> ptr = createPtr(2); 
    vec.push_back(ptr);//error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>' 
} 

Czy możesz mi wyjaśnić, dlaczego ten błąd i co jest poprawne wykorzystanie dla std::unique_ptr?

+1

Jaki jest sens przechowywania wskaźników do 'int' zamiast wartości w wektorze? –

+0

Jeśli rozważasz 'std :: unique_ptr <>', to prawdopodobnie * nie * masz "wektor obiektów", ale "wektor wskaźników do obiektów". Gdybyś miał "wektor obiektów", zniszczenie nastąpiłoby automatycznie. –

+0

@TadeuszKopec Proszę przeczytać pytanie – Felics

Odpowiedz

12

Rozważmy vec.push_back(). Ma dwa przeciążenia, które pobierają const std::unique_ptr<int>& lub std::unique_ptr<int>&&. Pierwsze przeciążenie może być nigdy nie będzie używane. Dzieje się tak, ponieważ vector<> wymaga, aby ten typ był możliwy do przypisania lub ruchomy (dodatek C++ 11). "Zbieżność" oznacza kopiowanie. push_back(const T&) spróbuje skopiować (przypisać) przychodzącą wartość do nowego miejsca na końcu kontenera. std::unique_ptr<> reprezentuje zasób, który jest własnością jednego właściciela. Kopiując go (wskaźnik) będzie obecnych wielu właścicieli. Z tego powodu unique_ptr nie można kopiować.

Po tym wszystkim można użyć tylko przeciążenia T&&.

createPtr() powraca std::unique_ptr<int>, ale jak to jest tymczasowy wynik (funkcja wartość zwracana) uważa się za odniesienia RValue (niejawnie). Dlatego można z niego korzystać.

ptr tylko std::unique_ptr<int> który jest lwartości odniesienia (bez względu na to, czy można umieścić & & obok niego, jak nazwane rvalues ​​są nadal traktowane jako lwartościami). L-wartość nigdy nie jest niejawnie przekształcana w wartość r (całkowicie niebezpieczne). Ale możesz po prostu powiedzieć kompilatorowi "Ok, możesz wziąć obiekt, który ci przekazuję, i obiecuję, że nie spodziewam się, że argument zostanie pozostawiony nietknięty" przy użyciu std::move().

14

Albo:

vec.push_back(std::move(ptr)); 

Lub:

vec.emplace_back(createPtr(2)); 
+1

To rozwiązuje problem, ale czy możesz wyjaśnić problem? – Felics

+7

@Felics Problem polega na tym, że 'unique_ptr' nie pozwala na konstruowanie kopii, więc próba' push_back' 'ptr' kończy się niepowodzeniem, ponieważ próbuje wywołać konstruktor kopiowania.Konstruktor przenoszenia jest jednak dostępny i oba rozwiązania Kerrek nazywają to, zamiast konstruktora kopiowania. – Praetorian

+0

@Praetorian Co z 'emplace_back'? – 0x499602D2

2

Masz unique_ptr:

std::unique_ptr<int> ptr = createPtr(2); 

Teraz można umieścić jego kopię w wektorze:

vec.push_back(ptr); 

Teraz masz dwie unique_ptr sz tej samej wartości. Gdyby było to dozwolone, nie byłoby to unikalne.

Powiązane problemy