2013-08-16 18 views
16

Jaki jest właściwy sposób przeniesienia własności na std::vector<unique_ptr<int> > na konstruowaną klasę?Prawidłowy sposób przeniesienia własności std :: vector <std :: unique_ptr < int>> na konstruowaną klasę

Poniżej przedstawiono kodową reprezentację tego, co chcę zrobić. Rozumiem, że nie jest poprawne (nie skompiluje) i narusza "wyjątkowość", niezależnie od tego, czy przekazuję wektor do konstruktora przez wartość lub przez odniesienie. Chcę, aby Foo był nowym właścicielem wektora i chce, aby funkcja wywołująca zrzekła się prawa własności. Czy potrzebuję konstruktora do zrobienia tego?

Foo.h

class Foo 
{ 
public: 
    Foo(vector<std::unique_ptr<int> > vecOfIntPtrsOwnedByCaller); 

private: 
    vector<std::unique_ptr<int> > _vecOfIntPtrsOwnedByFoo; 
} 

Foo.cpp

Foo::Foo(std::vector<std::unique_ptr< int> > vecOfIntPtrsOwnedByCaller) 
{ 
    _vecOfIntPtrsOwnedByFoo = vecOfIntPtrsOwnedByCaller; 
} 

Każda pomoc będzie mile widziane - Mam prane netto szukasz właściwy sposób to zrobić. Dzięki!

+1

'' std :: vector wymaga > albo tymczasowy lub wywołujący użycie 'std :: move' na własnym wektorze, ponieważ nie można go po prostu skopiować. Jeśli chcesz, aby było to naprawdę wyraźne, rozważ' std :: vector <...> && '. Następnie przejdź do swojego członka (w inicjatorach członków!) Za pomocą 'std :: move'. – Xeo

+1

Czy chcesz, aby wektor był unikatowy, czy zawarte w nim elementy? –

+0

Lekkość wyścigów na orbicie - obie. – Jen

Odpowiedz

16

std::unique_ptr<T> jest typu niekopiowanego, ale ruchomy. Posiadanie typu tylko do przeniesienia w std:vector<T> powoduje, że również std::vector<T> przesuwa się. Aby kompilator automatycznie przenosił obiekty, musisz mieć wartość r dla konstrukcji ruchu lub przeniesienia zadania. W twoim konstruktorze obiekt vecOfIntPtrsOwnedByCaller jest wartością l, chociaż taką, która pomimo swojej nazwy posiada już wskazane na int s: zostały "skradzione" od wywołującego, gdy wywołujący utworzył obiekt. Aby przejść z L-wartość, trzeba użyć std::move() (lub coś równoważnego):

Foo::Foo(std::vector<std::unique_ptr<int>> vecOfIntPtrsOwnedByCaller) 
{ 
    _vecOfIntPtrsOwnedByFoo = std::move(vecOfIntPtrsOwnedByCaller); 
} 

lub, korzystnie

Foo::Foo(std::vector<std::unique_ptr<int>> vecOfIntPtrsOwnedByCaller) 
    : _vecOfIntPtrsOwnedByFoo(std::move(vecOfIntPtrsOwnedByCaller)) 
{ 
} 

drugie podejście uniknąć pierwszy domyślnych konstruowania elementu a następnie move- przypisywanie do niego, a zamiast tego - przenoszenie elementu bezpośrednio. Sądzę, że sprawiłbym, że argument jest referencją do wartości r, ale nie jest to konieczne.

Uwaga, że ​​można budować obiektów typu Foo tylko z czegoś, co może być związany z R-wartość, np:

int main() { 
    Foo f0(std::vector<std::unique_ptr<int>>()); // OK 
    std::vector<std::unique_ptr<int>> v; 
    Foo f1(v); v// ERROR: using with an l-value 
    Foo f2{v}; v// ERROR: using with an l-value 
    Foo f3 = v; // ERROR: using with an l-value 
    Foo f4(std::move(v)); // OK: pretend that v is an r-value 
} 
+0

Czy rozwiązanie z referencją i zamianą jest prawidłowe? Mam na myśli to 'Foo (wektor > & v) {this-> v.swap (v); } '. Szczerze mówiąc, wiem, że twoja odpowiedź jest poprawna i lepsza - ale użycie 'swap' może być również sposobem na żądanie OP" przeniesienia własności "? – PiotrNycz

+0

@PiotrNycz: Używanie 'std :: vector <...>' 'swap()' też by działało, ale używanie 'std :: move()' na liście inicjalizatora członków jest idiomatycznym sposobem przesyłania zawartości. –

+0

Dziękuję Dietmar, czy mógłbybyś pokazać przykład konstruktora, który bierze również wartość rurnu i jak przekazać do niego wektor? Jak zdecydujesz, której wersji użyć? – Jen

Powiązane problemy