alf*_*lfC 9 iterator stl move const-iterator c++11
C++ 98容器定义了两种迭代器,::iterators和::const_iterators.一般来说,像这样:
struct vec{
iterator begin();
const_iterator begin() const;
};
Run Code Online (Sandbox Code Playgroud)
在C++ 11中,这部分设计似乎没有改变.问题是,
为了保持一致性和实际目的,添加::move_iterators也是有意义的吗?或者它是一种矫枉过正.
我可以想象一个右值容器可能会移动它们的元素.
class vec{
iterator begin() &;
const_iterator begin() const&;
move_iterator begin() &&;
};
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,可以在简单的情况下实现:
auto vec::begin() &&{return std::make_move_iterator(this->begin());}
Run Code Online (Sandbox Code Playgroud)
当然,普通的迭代器可以转换为移动迭代器(带std::make_move_iterator),但动机是通用代码.
例如,使用移动迭代器,这将非常优雅地实现,没有条件,具体取决于参数是左值还是右值.
template<class Container, class T = Container::value_type>
void transport_first(Container&& c, std::vector<T>& v){
v.emplace_back(*std::forward<Container>(c).begin());
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果可能,此代码不会产生任何不必要的副本.如何在没有move_iterators生成的情况下实现begin.
我也意识到这个问题几乎适用于容器的任何访问器,例如operator[],front()和back().
template<class Value>
class vec{
using value_type = Value;
using reference = Value&;
using const_reference = Value const&;
using rvalue_reference = Value&&; // NEW!
reference front() &{...}
rvalue_reference front() &&{...} // NEW!
const_reference front() const&{...}
};
Run Code Online (Sandbox Code Playgroud)
也许容器应该在C++ 11中从头开始重新设计.他们的设计显示了它的时代.
有一个建议,自动推导出(decl)类型,(*this)基本上具有所有相应的begin(和其他成员函数)的重载是免费的.
STL容器旨在与STL算法结合使用.目前在STL中找到的通用算法处理迭代器,但是你的模板函数transport_first:
template<class Container, class T = Container::value_type>
void transport_first(Container&& c, std::vector<T>& v){
v.emplace_back(*std::forward<Container>(c).begin());
}
Run Code Online (Sandbox Code Playgroud)
由基于容器的代码组成,即:它在容器而不是迭代器上运行.我们也许能够找到这样的基于容器的算法的STL为C++ 20个感谢的部分概念.
通用transport_first算法的"类STL方法" 实际上是:
template<typename InIt, typename OutIt>
void transport_first(InIt src, OutIt dst) {
*dst = *src;
}
Run Code Online (Sandbox Code Playgroud)
遵循这种方法(即:迭代器而不是容器),当涉及到通用代码时,是否使用是否move_iterator可以简单地在"最顶层"通用算法中确定,因为传递的迭代器被进一步复制(即:通过值传递)进入"潜在的"算法).
另外,与transport_first上面基于迭代器的不同,STL充满了基于迭代器对的算法(例如:) std::copy来实现范围.这个接口使得在rvalues上重载那些容器成员函数没什么吸引力,因为正如在另一个答案中已经说明的那样,那些重载的成员函数将被调用,尤其是在未命名的(非const)容器对象上,并且未命名的容器对象被限制为在单个表达式中使用,通过在同一容器对象上调用两个和成员函数来阻止迭代器对的创建.begin()end()
对容器真正有意义的是,有新的新成员函数来返回相应的move_iterator对象:
move_iterator Container<T>::mbegin();
move_iterator Container<T>::mend();
Run Code Online (Sandbox Code Playgroud)
这只是使用std::make_move_iterator返回的成员函数返回的值调用的快捷方式iterator.成员函数mbegin()将在基于迭代器的函数中使用transport_first:
transport_first(coll.mbegin(), std::back_inserter(vec));
Run Code Online (Sandbox Code Playgroud)
相应的函数模板std::mbegin()和std::mend()也将使意义:
transport_first(std::mbegin(coll), std::back_inserter(vec));
Run Code Online (Sandbox Code Playgroud)
您可以轻松地将任何非常量迭代器转换为移动迭代器。它通常对容器没有影响。
您不能轻易地将非常量迭代器转换为常量迭代器。例如,当采用非常量迭代器(使用 )时,写时复制字符串(std::string过去对于某些编译器来说,自定义字符串仍然可能是这样)必须悲观地从共享数据中分离,begin()以便满足典型的失效保证,当你只想要一个常量迭代器时,这是非常低效的。
此外,C++ 重载规则不允许您在begin()不将未指定版本更改为左值的情况下引入右值重载,这将是一个重大更改。
最后,重载begin()右值无论如何都没有用 - 期望是在右值上调用右值函数,并且除了 产生的右值之外std::move,这些右值 1) 很快就会消失(这将使获得的迭代器无效)并且 2) 没有名称,这意味着它们只能在一个表达式中使用,这意味着您不能同时调用begin()和end()来获取迭代器对,并且单个迭代器是无用的,因为您永远无法知道取消引用它是否安全。
| 归档时间: |
|
| 查看次数: |
269 次 |
| 最近记录: |