1

Looking at cppreference, I see:

vector( const vector& other, const Allocator& alloc ); // copy constructor
vector( vector&& other ); // move constructor

I'd like to form one vector from another vector's instance (stealing its contents as efficiently as possible), is this the way to do it:

vector<double>my_vec(std::move(my_other_vec)); // move construction
my_vec = std::move(my_other_vec); // move assignment

and if so, in order to call the move constructor over the copy, is it always required to pass in the function call to std::move?

Would I then be able to use my_other_vec as an empty vector to do stuff with?

  • 3
    If `my_vec` is a live object, you cannot call its "move *constructor*" because the object... has been *constructed*. You can call its move *assignment* operator. – Nicol Bolas Dec 30 '22 at 22:26
  • Yes, this is the way, you don't even need to call the constructor, just `my_vec = std::move(my_other_vec)`. There are no reasonable alternatives. Technically it's all about type casting and `static_cast` and `std::move` is effectively no-op. Other stuff like `std::forward` for perfect forwarding is the same, with some technical bits thrown in. – yeputons Dec 30 '22 at 22:26
  • Thanks for the clarification @NicolBolas . Would all three of the ways I mentioned above be equivalent in doing so? Perhaps the last is the most explicit. – user20896951 Dec 30 '22 at 22:27
  • So really `std::move` is just a wrapper to make sure that it gets passed in to the right overloaded function call @yeputons ? – user20896951 Dec 30 '22 at 22:28
  • @user20896951 More or less, see [here](https://stackoverflow.com/questions/3413470/what-is-stdmove-and-when-should-it-be-used). – yeputons Dec 30 '22 at 22:32
  • I see. So what if I'd still like to use `my_other_vec` but I'd like it to be empty? @yeputons – user20896951 Dec 30 '22 at 22:33
  • You can also use std::swap(), which does the same thing, is fool-proof, very explicit, and leaves the donor vector in a valid state 100% of the time. – Michaël Roy Dec 30 '22 at 22:34
  • Thanks @MichaëlRoy . I just wrote this: `vector temp(std::move(m_B)); m_B = std::move(m_C); m_C = std::move(temp);` you're saying it's the same as `std::swap(m_B, m_C);` ? – user20896951 Dec 30 '22 at 22:37
  • 2
    @user20896951 for that example `std::swap` is better because it'd use the one [specialized for `vector`](https://en.cppreference.com/w/cpp/container/vector/swap2) – apple apple Dec 30 '22 at 22:48
  • @user20896951 You still can use `my_other_vec` after moving out from it. It's in a valid state, but it's unspecified what it is exactly. You have to call `my_other_vec.clear()` afterwards. – yeputons Dec 30 '22 at 23:31

1 Answers1

0

You can call move constructor directly by calling removed reference into it directly. For example

#include <vector>
#include <iostream>

template<class I>
void print_all(I begin, I end)
{
  std::cout << '[';
  if(begin != end) {
    std::cout << *begin;
    while(++begin != end) {
        std::cout << ',' << *begin;
    }
  }
  std::cout << ']' << std::endl;
}

int main(int argc, const char** argv) 
{    
  std::vector<int> src  {{0,1,2,3,4,5,6,7}};
  std::cout << "Before movement: ";
  print_all(src.begin(), src.end());
  std::vector<int> dst( std::move(src) );
  std::cout << "After movement: ";
  print_all(src.begin(), src.end());
  std::cout << "Moved: ";
  print_all(dst.begin(), dst.end());
  return 0;
}

It will returns you:

Before movement: [0,1,2,3,4,5,6,7]
After movement: []
Moved: [0,1,2,3,4,5,6,7] 

As you can see, vector's data moved from one instance to another. You can use vector::swap for the same behavior.

Victor Gubin
  • 2,782
  • 10
  • 24
  • I don't believe `std::swap` is the same behavior. It leaves both in a valid state, yours leaves `src` in an invalid state. – user20896951 Dec 30 '22 at 22:47
  • `std::vector src {{0,1,2,3}}; std::vector dst; dst,.swap(src);` ? Actually this is what most of container movement constructor doing, is in it? – Victor Gubin Dec 30 '22 at 22:49
  • BTW according to the [documentation](https://en.cppreference.com/w/cpp/container/vector/vector) _8) Move constructor. Constructs the container with the contents of other using move semantics. Allocator is obtained by move-construction from the allocator belonging to other. After the move, other is guaranteed to be empty()._ I.e. state and behavior is defined. Off cause semantically code with swap looks nicer. – Victor Gubin Dec 30 '22 at 22:52
  • @user20896951 After a mpove, the donor vector is not in an invalid state, burt in an unspecoified (aka unknown) state. Granted that's almsot the same. After a swap, the donor is in a known state, which means it owns the memory buffer allocated by the target (if any), that can be useful in some cases.. – Michaël Roy Dec 30 '22 at 23:59
  • @MichaëlRoy doesn't that contradict what victor stated? It is guaranteed to be `empty()` after it has been moved from. – user20896951 Dec 31 '22 at 00:45
  • @user20896951 According to the standard, that's maybe empty. – Michaël Roy Dec 31 '22 at 12:27
  • So "BTW according to the documentation 8) Move constructor. Constructs the container with the contents of other using move semantics. Allocator is obtained by move-construction from the allocator belonging to other. After the move, other is guaranteed to be empty(). I.e. state and behavior is defined." is incorect @MichaëlRoy ? – user20896951 Dec 31 '22 at 20:45
  • I got my information from https://en.cppreference.com/w/cpp/container/vector/operator%3D – Michaël Roy Dec 31 '22 at 22:35