I'm trying to return a tuple, one of the elements of which is a std::unique_ptr
. I want to transfer the ownership of the unique_ptr
to the caller. How do I do this?
#include <tuple>
#include <memory>
#include <iostream>
using namespace std;
class B
{
public:
B(int i) : i_(i) {}
int getI() const { return i_; }
private:
int i_;
};
tuple<unique_ptr<B>, int>
getThem()
{
unique_ptr<B> ptr(new B(10));
return make_tuple(ptr, 50);
}
int
main(int argc, char *argv[])
{
unique_ptr<B> b;
int got = 0;
tie(b, got) = getThem();
cout << "b: " << b->getI() << endl;
cout << "got: " << got << endl;
return 0;
}
This fails to compile because the copy constructor of unique_ptr
is deleted, for obvious reasons. But how to I indicate I want to move the unique_ptr
into the tie
?
If a function returns a std::unique_ptr<> , that means the caller takes ownership of the returned object. class Base { ... }; class Derived : public Base { ... }; // Foo takes ownership of |base|, and the caller takes ownership of the returned // object.
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.
This means that a unique_ptr can be assigned to the unique_ptr returned from a function, but you can't assign one declared unique_ptr to another. But if you invoke a move assignment (with std::move) you can assign them, but the lhs unique_ptr now owns the object and the rhs now owns nothing.
Yes, you can compare it to nullptr after the move and it is guaranteed to compare equal. This is clearly true after calling release().
Essentially you just need to explicitly move the non-copyable types into the tuple, thus using std::move
. std::tuple
has the appropriate constructors to copy and move the types internally (the move being appropriate here).
As follows;
#include <tuple>
#include <memory>
#include <iostream>
using namespace std;
class B
{
public:
B(int i) : i_(i) {}
int getI() const { return i_; }
private:
int i_;
};
tuple<unique_ptr<B>, int>
getThem()
{
unique_ptr<B> ptr(new B(10));
return make_tuple(std::move(ptr), 50); // move the unique_ptr into the tuple
}
int
main(int argc, char *argv[])
{
unique_ptr<B> b;
int got = 0;
tie(b, got) = getThem();
cout << "b: " << b->getI() << endl;
cout << "got: " << got << endl;
return 0;
}
Use std::move
to invoke the move operator instead.
return make_tuple(std::move(ptr), 50);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With