move_iterator 是什么意思

What is move_iterator for

如果我理解正确,a=std::move(b) 将引用 a 绑定到 b 的地址。而且这样操作后b指向的内容就不能保证了

move_iterator here 的实现有这一行

auto operator[](difference_type n) const -> decltype(std::move(current[n]))
  { return std::move(current[n]); }

但是,我认为 std::move 数组中的元素没有意义。如果 a=std::move(b[n]) 会发生什么?

下面的例子也让我很困惑:

std::string concat = std::accumulate(
                             std::move_iterator<iter_t>(source.begin()),
                             std::move_iterator<iter_t>(source.end()),
                             std::string("1234"));

由于concat本身会分配一块连续的内存来存储结果,不会与source有任何重叠。 source 中的数据将被复制到 concat 但不会移动。

move_iterator 的目的是为算法提供其输入的右值。

您的示例 auto a=std::move(b[n]) 没有移动数组中的值,而是将其移出数组,这是明智之举。

你的 std::accumulate 中的技巧是 operator+ for std::string 的定义(记住 accumulate 的默认版本使用 operator+。它对右值参数进行了特殊优化。对于我们的案例重载编号 7 是重要的,因为 accumulate 使用表达式 init + *begin。这将尝试重用右侧参数的内存。如果这实际上证明是优化,则不是很清楚。

http://en.cppreference.com/w/cpp/iterator/move_iterator 是这样说的:

std::move_iterator is an iterator adaptor which behaves exactly like the underlying iterator (which must be at least an InputIterator), except that dereferencing converts the value returned by the underlying iterator into an rvalue.

大多数(如果不是全部)接受范围的标准算法,从范围的开头到结尾遍历迭代器,并对取消引用的迭代器执行操作。例如,std::accumulate 可能实现为:

template <class InputIterator, class T>
T accumulate (InputIterator first, InputIterator last, T init)
{
  while (first!=last) {
    init = init + *first;
    ++first;
  }
  return init;
}

如果 firstlast 是普通迭代器(调用是

std::accumulate(source.begin(), source.end(), std::string("1234"));

,则*first是对字符串的左值引用,表达式init + *first将调用std::operator+(std::string const&, std::string const&)(重载1here)。

但是,如果调用是

std::accumulate(std::make_move_iterator(source.begin()), std::make_move_iterator(source.end()), std::string("1234"));

然后在 std::accumulate 中,firstlast 是移动迭代器,因此 *first 是一个右值引用。这意味着 init + *first 改为调用 std::operator+(std::string const&, std::string &&)(重载 7)。

If I understand it correct, a=std::move(b) binds reference a to the address of b. And after this operation the content that b points to is not guaranteed.

啊,不:a 不一定 参考。 std::move 的上述用法还授予编译器调用 decltype(a)::operator=(decltype(b)&&)(如果存在)的权限:此类赋值运算符在 a 的赋值期间使用 b 的值不需要被保存,但 b 仍必须保持 一些 正常状态以供销毁。

However, I don't think it makes sense to std::move an element in an array. What happens if a=std::move(b[n])?

它是有道理的……它只是意味着每个数组元素都可以有效地 assigned/moved 到另一个变量,但每个元素只有一次。在移动它们之后,正确编写的移动构造函数或赋值运算符应该使对象处于有效但未指定的状态,这意味着您通常希望在读取它们之前再次设置它们。

我的 展示了某人如何 append/move 从 listvector 的元素。使用当前的 C++ 标准,您可以像那样直接创建 move_iterators。

下面的代码显示了如何 - 即使使用较旧的编译器/C++ 标准 - 如果您想从源迭代器范围内的元素移动,make_move_iterator 也可以与 std::copy 一起使用。

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

struct X
{
    X(int n) : n_(n) { }
    X(const X& rhs) : n_(rhs.n_) { }
    X(X&& rhs) : n_{ rhs.n_ } { rhs.n_ *= -1; std::cout << "=(X&&) "; }
    X& operator=(X&& rhs) { n_ = rhs.n_; rhs.n_ *= -1; std::cout << "=(X&&) "; return *this; }
    int n_;
};

int main()
{
    std::vector<X> v{2, 1, 8, 3, 4, 5, 6};
    std::vector<X> v2{};

    std::copy(v.begin() + 2, v.end(), std::insert_iterator(v2, v2.end()));
    for (auto& x : v)
        std::cout << x.n_ << ' ';
    std::cout << '\n';

    std::copy(std::make_move_iterator(v.begin() + 2), std::make_move_iterator(v.end()), std::insert_iterator(v2, v2.end()));
    for (auto& x : v)
        std::cout << x.n_ << ' ';
    std::cout << '\n';
}

输出:

2 1 8 3 4 5 6 
=(X&&) =(X&&) =(X&&) =(X&&) =(X&&) 2 1 -8 -3 -4 -5 -6 

代码可以 运行 / 在 coliru 上编辑。