Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move unique_ptr from set to set

Tags:

c++

c++11

stl

I can't seem to figure this out and have tried the suggestions in:

Move `unique_ptr`s between sets

how to move an std::unique_ptr<> from one STL container to another?

I have two sets containing unique pointers:

std::set<std::unique_ptr<some_type>> s1, s2;

The pointers are of course unique but the values of some_type may or may not be, so after joining the s2 into s1, s1's size may be the same or as large as |s1 + s2|.

It seems like I should be able to do this:

move(s2.begin(), s2.end(), inserter(s1, s1.end()));

But this fails with clang++ 3.8 / g++ 5.4.

What am missing here?

like image 787
user318904 Avatar asked Oct 21 '16 23:10

user318904


People also ask

Can unique_ptr be moved?

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.

How do I transfer ownership of unique PTRS?

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 assign a unique_ptr?

It can be assigned: class owner { std::unique_ptr<someObject> owned; public: owner() { owned=std::unique_ptr<someObject>(new someObject()); } };

What does get () do on a unique_ptr?

unique_ptr::getReturns a pointer to the managed object or nullptr if no object is owned.


1 Answers

It doesn't work because a std::set only gives const access to its elements. There is no way to move something out of a std::set. See Is it possible to move an item out of a std::set?

There's no good way to do this in C++14, but in C++17 there is a merge method provided for this purpose, which simply rearranges the internal pointers of the data structures without copying or moving any elements:

s1.merge(s2);

A somewhat reasonable workaround in C++14 is to change std::set<std::unique_ptr<T>> to std::map<T*, std::unique_ptr<T>>. Then you can do:

while (!s1.empty()) {
    s2[s1.begin()->first] = std::move(s1.begin()->second);
    s1.erase(s1.begin());
}
like image 117
Brian Bi Avatar answered Oct 22 '22 17:10

Brian Bi