1

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
sorush-r
  • 10,490
  • 17
  • 89
  • 173

5 Answers5

6

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;
}
Vaughn Cato
  • 63,448
  • 5
  • 82
  • 132
6

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()));
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
1

Do it elementwise.

for (auto&& elem : v2)
{
    v1.push_back(std::move(elem));
}
isarandi
  • 3,120
  • 25
  • 35
0

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());
Jarod42
  • 203,559
  • 14
  • 181
  • 302
0
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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524