std::move和std::copy是否相同

Are std::move and std::copy identical?

本文关键字:std 是否 move copy      更新时间:2023-10-16

我试着做一些类似的事情:

std::copy(std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end()), 
          std::make_move_iterator(s2.begin()));

得到了这个错误:

error: using xvalue (rvalue reference) as lvalue
        *__result = std::move(*__first);

这似乎让我感到困惑。如果你使用std::move,同样的事情也会发生。GCC内部似乎使用了一个名为std::__copy_move_a的函数,该函数用于移动而非复制。使用std::copy还是std::move有关系吗?


#include <string>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <cstring>
struct Test
{
    typedef std::string::value_type value_type;
    std::string data;
    Test()
    {
    }
    Test(const char* data)
        : data(data)
    {
    }
    ~Test()
    {
    }
    Test(const Test& other)
        : data(other.data)
    {
        std::cout << "Copy constructor.n";
    }
    Test& operator=(const Test& other)
    {
        data = other.data;
        std::cout << "Copy assignment operator.n";
        return *this;
    }
    Test(Test&& other)
        : data(std::move(other.data))
    {
        std::cout << "Move constructor.n";
    }
    decltype(data.begin()) begin()
    {
        return data.begin();
    }
    decltype(data.end()) end()
    {
        return data.end();
    }
    void push_back( std::string::value_type ch )
    {
        data.push_back(ch);
    }
};
int main()
{
    Test s1("test");
    Test s2("four");
    std::copy(std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end()), 
              std::make_move_iterator(s2.begin()));
    std::cout << s2.data;
}

std::move(a, b, c);在语义上与相同

std::copy(std::make_move_iterator(a),
          std::make_move_iterator(b),
          c);

您使用它们的努力都失败了,因为第三个参数-输出迭代器-应该而不是是移动迭代器。您正在存储到第三个迭代器中,而不是从中移动

std::copy(std::make_move_iterator(s1.begin()),
          std::make_move_iterator(s1.end()),
          s2.begin());

std::move(s1.begin(), s1.end(), s2.begin());

应该做你想做的事。

std::move尽可能移动元素,否则进行复制。std::copy将始终复制。

libstdc++的copy_move_a还采用了一个模板参数_IsMove。这以及迭代器类型,它委托给一个__copy_move类模板,该模板部分专门用于不同的迭代器类别等,但最重要的是:是否委托给move。其中一个专业是

#if __cplusplus >= 201103L
  template<typename _Category>
    struct __copy_move<true, false, _Category>
    // first specialized template argument is whether to move
    {
      template<typename _II, typename _OI>
        static _OI
        __copy_m(_II __first, _II __last, _OI __result)
        {
      for (; __first != __last; ++__result, ++__first)
        *__result = std::move(*__first); // That may be your line
      return __result;
    }
    };
#endif

您的代码编译失败的原因完全不同:第二个范围是通过move_iterators给出的。如果您取消引用它们,它们将返回对对象的右值引用,并且您不能为标量类型的xvalue赋值。

int i;
std::move(i) = 7; // "expression not assignable" -- basically what your code does

std::move隐含地包括在*__result中,并且具有相同的值类别,即x值。

举个例子,

std::copy(std::make_move_iterator(s1.begin()), std::make_move_iterator(s1.end()),
          s2.begin());

应该可以正常工作。

相关文章: