Search code examples
c++c++11iteratormovestdvector

What is the benefit of moving a range of elements in a vector vs. copying?


Consider the following snippet (saw something analogous to this in a large simulation code)

std::vector<int> v1{1,2,3,4,5,6,7};
std::vector<int> v2;

std::move(v1.begin() + 2, v1.end(), back_inserter(v2));

Here, I am moving a range of elements from v1 to v2, but is there any particular advantage to doing this vs. copying? I do not actually see what the advantage of the move here would be since it's operating on a range of ints. In fact, I do not believe any move is occurring since we are dealing with POD types.

If we instead wanted to transfer the entire v1 to v2, then we could do:

v2 = std::move(v1);

The cast here would allow v2 to now own the pointer to the contiguous range of memory previously owned by v1, thus avoiding a copy.

But in the former move of a range of elements, I do not see the usefulness.


Solution

  • Here, I am moving a range of elements from v1 to v2, but is there any particular advantage to doing this vs. copying?

    No. Here is all happened just a range coping, because your usage of std::move for primitive types just do coping. Therefore it does the same as simple if you would have:

    std::vector<int> v2{v1.begin() + 2, v1.end()};
    

    Therefore you are correct about the findings. However, it is called fundamental types/ primitive types, not PODs.


    But in the former move of a range of elements, I don't see the usefulness.

    Consider the case of std::vector</*expensive copy type*/>, in which it makes sense to have a move of the underlying range elements, whenever is possible.

    For instance consider the std::vector<std::string> case

    std::vector<std::string> v1{ "1","2","3","4","5","6","7" };
    std::vector<std::string> v2;
    // reserve memory for unwanted reallocations
    v2.reserve(std::distance(v1.begin() + 2, v1.end()));
    
    // moves the string element in the range
    std::move(v1.begin() + 2, v1.end(), back_inserter(v2));
    
    // v1 now: 1 2
    // v2 now: 3 4 5 6 7 
    

    (See a demo here)


    As a side note, instead of std::move the range in a separate line, for iterators, one could also use std::make_move_iterator, to do the range move construction while declaration (if make sence).

    #include <iterator> // std::make_move_iterator
    
    std::vector<std::string> v1{ "1","2","3","4","5","6","7" };
    std::vector<std::string> v2{ std::make_move_iterator(v1.begin() + 2),
       std::make_move_iterator(v1.end()) };