Soroush Rabiei
Soroush Rabiei

Reputation: 10868

Move vector<unique_ptr<Derived>> to a vector<unique_ptr<Base>>

I have two classes, say Base and Derived: public Base and two std::vectors, one holding elements of type unique_ptr<Base> and other one holds elements of type unique_ptr<Derived> How can I transfer ownership of all elements from second vector into first one? I already tried:

vector<unique_ptr<Base>> v1;
vector<unique_ptr<Derived>> v2;
// do something
std::move(v2.begin(),v2.end(),v1.begin()); // This line crashed
v1 = std::move(v2); // And this gives a compiler error

Upvotes: 1

Views: 1716

Answers (5)

Howard Hinnant
Howard Hinnant

Reputation: 218790

As I did not see this answer elsewhere, I wanted to remind everyone of the very simple member function assign of vector:

vector<unique_ptr<Base>> v1;
vector<unique_ptr<Derived>> v2;
// do something
v1.assign(make_move_iterator(v2.begin()), make_move_iterator(v2.end()));

Upvotes: 6

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275435

template<class Dest, class Src>
void move_contents_to(Dest&dest, Src const& src)=delete;
template<class Dest, class Src>
void move_contents_to(Dest&dest, Src& src)=delete;
template<class Dest, class Src>
void move_contents_to(Dest&dest, Src&& src){
  using std::begin; using std::end;
  dest = Dest{std::make_move_iterator(begin(src)),std::make_move_iterator(end(src))};
}

the above will work for most std containers, and will work with raw C style arrays on the right. For safety, I require the src to be an rvalue reference, so which is being moved is clear.

Upvotes: 0

Vaughn Cato
Vaughn Cato

Reputation: 64308

You need to make sure v1 is the proper size before moving into it. For example:

#include <algorithm>
#include <vector>
#include <memory>

using std::vector;
using std::unique_ptr;

struct Base {
};

struct Derived : Base {
};

int main()
{
  vector<unique_ptr<Base>> v1;
  vector<unique_ptr<Derived>> v2;
  v2.push_back(unique_ptr<Derived>(new Derived));
  v2.push_back(unique_ptr<Derived>(new Derived));
  v2.push_back(unique_ptr<Derived>(new Derived));
  v1.resize(v2.size());
  std::move(v2.begin(),v2.end(),v1.begin());
}

This is because the move algorithm doesn't change the size of the container itself. It is implemented like this (taken from http://en.cppreference.com/w/cpp/algorithm/move):

template<class InputIt, class OutputIt>
OutputIt move(InputIt first, InputIt last, OutputIt d_first)
{
    while (first != last) {
        *d_first++ = std::move(*first++);
    }
    return d_first;
}

Upvotes: 6

Jarod42
Jarod42

Reputation: 217358

You may use the following:

std::vector<std::unique_ptr<Base>> v1(v2.size());

std::copy(std::make_move_iterator(v2.begin()), std::make_move_iterator(v2.end()), v1.begin());

Upvotes: 0

isarandi
isarandi

Reputation: 3349

Do it elementwise.

for (auto&& elem : v2)
{
    v1.push_back(std::move(elem));
}

Upvotes: 1

Related Questions