Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper way of transferring ownership of a std::vector< std::unique_ptr< int> > to a class being constructed

What is the proper way of transferring ownership of a std::vector<unique_ptr<int> > to a class being constructed?

Below is a code representation of what I want to do. I realize it is not correct (won't compile) and violates "uniqueness" whether I pass the vector to the constructor by value or by reference. I want Foo to be the new owner of the vector, and want the calling function to relinquish ownership. Do I need the constructor to take a std::unique_ptr<std::vector<std::unique_ptr<int> > > to do this?

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; } 

Any help would be much appreciated - I've scoured the net looking for the correct way to do this. Thanks!

like image 759
Jen Avatar asked Aug 16 '13 21:08

Jen


People also ask

How do you transfer ownership of an object in C++?

In C++11 we can transfer the ownership of an object to another unique_ptr using std::move() . After the ownership transfer, the smart pointer that ceded the ownership becomes null and get() returns nullptr.

Can you move a unique_ptr?

A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to another unique_ptr and the original unique_ptr no longer owns it. We recommend that you restrict an object to one owner, because multiple ownership adds complexity to the program logic.

Can unique_ptr be copied?

unique_ptr is not copyable, it is only moveable. This will directly affect Test, which is, in your second, example also only moveable and not copyable. In fact, it is good that you use unique_ptr which protects you from a big mistake.

Can I have a vector of unique_ptr?

This means that you can't make copies of a unique_ptr (because then two unique_ptr s would have ownership), so you can only move it. D.R. Since there can be only one, one should also be able to pass a temporary directly to the vector: vec. push_back(std::unique_ptr<int>(new int(1))); .


1 Answers

std::unique_ptr<T> is a non-copyable but movable type. Having a move-only type in a std:vector<T> make the std::vector<T> move-only, too. To have the compiler automatically move objects, you need to have an r-value for move-construction or move-assignment. Within your constructor the object vecOfIntPtrsOwnedByCaller is an l-value, although one which, despite its name, already owns the pointed to ints: they got "stolen" from the caller when the caller created the object. To move from an l-value, you need to use std::move() (or something equivalent):

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

or, preferable

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

The latter approach avoid first default-constructing the member and then move-assigning to it and, instead, move-constructs the member directly. I guess, I would also make the argument an r-value reference but this isn't necessary.

Note, that you can construct objects of type Foo only from something which can be bound to an r-value, e.g.:

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 } 
like image 76
Dietmar Kühl Avatar answered Oct 04 '22 04:10

Dietmar Kühl