27

If I have two vectors and want to combine them to one, I can do it the following way:

std::vector<T> a(100); // just some random size here
std::vector<T> b(100);

a.insert(std::end(a), std::begin(b), std::end(b));

That involves copying though, which I want to avoid. Is there any way to use move-semantics to get them together?
I highly doubt it, as a vector is supposed to be contiguous. However is there any way to do it with a deque?

Stephan Dollberg
  • 32,985
  • 16
  • 81
  • 107

2 Answers2

51

Yes, use std::move:

#include <algorithm>
std::move(b.begin(), b.end(), std::back_inserter(a));

Alternatively, you can use move iterators:

a.insert(a.end(),
         std::make_move_iterator(b.begin()), std::make_move_iterator(b.end()));

Remember to #include <iterator> in both cases, and before you begin, say:

a.reserve(a.size() + b.size());

Depending on the cost of value-initialization compared to checking and incrementing the size counter, the following variant may also be interesting:

std::size_t n = a.size();
a.resize(a.size() + b.size());
std::move(b.begin(), b.end(), a.begin() + n);
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Thanks, now I know why there are two versions of `std::move` on cppreference. I always thought that was a bug and didn't check the second version out. – Stephan Dollberg Mar 19 '12 at 21:55
  • 3
    I had completely missed that `move` was also an algorithm. – bames53 Mar 19 '12 at 21:59
  • @bames53 the same happend to me, but after hearing it, it makes total sense as there is also `copy`. – Stephan Dollberg Mar 19 '12 at 22:01
  • Wow i didn't know this was available. Great answer. – 111111 Mar 19 '12 at 22:10
  • You cannot generalize this solution and hope that vectors will be always moved in place (without any new allocation). How will you guarantee that the merged vectors are contiguous in memory? – mustafabar Dec 12 '14 at 21:43
  • 1
    @mustafabar: `std::vector` guarantees contiguous storage. Indeed this may require reallocation. There is no way in general to magically make two separate parts of memory become one contiguous part without copying some of the memory content somehow. – Kerrek SB Dec 12 '14 at 23:27
  • 1
    @KerrekSB, that's right. I am trying to understand here. so the advantage of using "move range" is that the nodes won't be reconstructed, they will rather be just moved, and the source vectors pointers will be invalidated?, whereas if you use the "move constructor", there's no newly allocated memory on top of that – mustafabar Dec 14 '14 at 19:19
  • @mustafabar As far as I know move_iterator move elements no vectors. – S.R Aug 09 '17 at 15:39
8

Depends on exactly what you want to move. When you move a vector, it is done by effectively swapping the internal array pointer. So you can make one vector point to the array previously owned by another vector.

But that won't let you merge two vectors.

The best you can do then is to move every individual member element, as shown in Kerrek's answer:

std::move(b.begin(), b.end(), std::back_inserter(a));

Again, this will iterate through the vector and move every element to the target vector.

jalf
  • 243,077
  • 51
  • 345
  • 550
  • A question, what difference does it make though? Aren't we essentially copying the objects in a into the positions at b ? Won't it do the same thing as insert as in the op's question ? – nnrales Nov 29 '16 at 00:21
  • I suppose if the objects in a are complex, then their copy ctors will not be called, just a memory copy ? – nnrales Nov 29 '16 at 00:22