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;
}
如果 first
和 last
是普通迭代器(调用是
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 中,first
和 last
是移动迭代器,因此 *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 从 list
到 vector
的元素。使用当前的 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 上编辑。
如果我理解正确,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;
}
如果 first
和 last
是普通迭代器(调用是
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 中,first
和 last
是移动迭代器,因此 *first
是一个右值引用。这意味着 init + *first
改为调用 std::operator+(std::string const&, std::string &&)
(重载 7)。
If I understand it correct,
a=std::move(b)
binds referencea
to the address ofb
. 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 ifa=std::move(b[n])
?
它是有道理的……它只是意味着每个数组元素都可以有效地 assigned/moved 到另一个变量,但每个元素只有一次。在移动它们之后,正确编写的移动构造函数或赋值运算符应该使对象处于有效但未指定的状态,这意味着您通常希望在读取它们之前再次设置它们。
我的 list
到 vector
的元素。使用当前的 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 上编辑。