C++11 移动容器的迭代器?

C++11 移动容器的迭代器?,c++11,stl,iterator,move,const-iterator,C++11,Stl,Iterator,Move,Const Iterator,C++98容器定义了两种迭代器::迭代器和::const_迭代器。一般来说,像这样: struct vec{ iterator begin() ; const_iterator begin() const; }; 在C++11中,这部分设计似乎没有改变。 问题是,, 出于一致性和实际目的,添加::move_迭代器是否也有意义?或者这是一种过度的杀伤力 我可以想象,如果可能的话,一个右值容器可能会移动它们的元素 class vec{ itera

C++98容器定义了两种迭代器::迭代器和::const_迭代器。一般来说,像这样:

struct vec{
         iterator begin()      ;
   const_iterator begin() const;
};
在C++11中,这部分设计似乎没有改变。 问题是,, 出于一致性和实际目的,添加::move_迭代器是否也有意义?或者这是一种过度的杀伤力

我可以想象,如果可能的话,一个右值容器可能会移动它们的元素

class vec{
         iterator begin()      &;
   const_iterator begin() const&;
   move_iterator  begin()     &&;
};
如果我理解正确,它可以在简单的情况下实现如下:

auto vec::begin() &&{return std::make_move_iterator(this->begin());}
当然,普通迭代器可以通过std::make_move_迭代器转换为move迭代器,但是动机是通用代码

例如,使用移动迭代器,这将非常优雅地实现,而无需依赖于参数是左值还是右值的条件

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());
}
也许容器应该在C++11中从头开始重新设计。 他们的设计正显示出它的时代

有一个建议是,自动推断*的decltype,它基本上免费拥有begin和其他成员函数的所有相应重载


您可以轻松地将任何非常量迭代器转换为移动迭代器。它通常对容器没有影响

不能简单地将非常量迭代器转换为常量迭代器。例如,写时复制字符串std::string在过去,对于某些编译器来说,自定义字符串仍然可能是这样的:当使用begin获取非常量迭代器时,为了实现典型的无效保证,这必须悲观地从共享数据中分离,当您只需要常量迭代器时,这是非常低效的

此外,C++重载规则不允许您在不将未指定版本更改为LValk的情况下引入Read重载的起始值,这将是一个突破性的改变。


最后,在右值上重载begin是没有用的-期望是在右值上调用右值函数,并且除了那些由std::move生成的函数外,这些右值1将很快消失,这将使获得的迭代器无效,而2没有名称,这意味着它们只能在一个表达式中使用,这意味着您不能同时调用begin和end来获得迭代器对,而单个迭代器是无用的,因为您永远不知道取消引用它是否安全。

STL容器设计为与STL算法结合使用。当前在STL中找到的通用算法处理迭代器,但模板函数首先传输\u:

按照这种方法,即:迭代器而不是容器,当涉及到泛型代码时,可以在最顶层的泛型算法上简单地确定是否使用move_迭代器,因为传递的迭代器会被进一步复制,即:按值传递到底层算法中

此外,与上面第一个基于迭代器的传输单元不同,STL充满了基于迭代器对的算法,例如:std::copy to implementation ranges。此接口使得在右值上重载这些容器成员函数没有什么吸引力,因为如中所述,这些重载的成员函数将在未命名的非常量容器对象上调用,并且未命名的容器对象仅限于在单个表达式中使用,通过在同一容器对象上同时调用begin和end成员函数来阻止迭代器对的创建

对于容器来说,真正有意义的是使用新的成员函数返回相应的move_迭代器对象:

相应的函数模板std::mbegin和std::mend也有意义:

transport_first(std::mbegin(coll), std::back_inserter(vec));

我不明白你为什么说没有将未指定的版本更改为左值,这将是一个突破性的更改。即使这会破坏代码,但如果容器可以重做,这不是一个好主意吗?新设计的集装箱呢?当然,普通迭代器可以通过std::make_move_迭代器转换为move迭代器,但是动机是通用代码。要知道make_move_迭代器是否可以应用,基本上有时为时已晚。请参阅我现在在问题中输入的示例代码;myback=*std::forwardcont.rbegin是一个很好的例子,说明了为什么这个重载很有用。请看这里,调用forward两次并不意味着对象立即失效,特别是因为调用begin首先不应该使任何东西失效。。。是的,我会相信的,这是讽刺吗?我的意思是,begin语义上的意思是指向第一个元素,当然可以编写一个非常平均的begin,但这里的问题是关于容器当前begin的良好/有用的泛化。我的意思是,我不相信任何调用右值引用的方法不会修改对象,我认为这样做是愚蠢的。另外,如果容器只包含一个元素,代码就会中断。这就是我遵循的路径,fir st我添加了mbegin和mend,类似于cbegin和cend,然后我意识到最好实现begin&&和end&&来推断对mbegin和mend的调用,自动类似于begin const和end const所做的,然后我问了这个问题。请参见此处:,建议通过添加一个语言特性来实现所有的重载。
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());
}
template<typename InIt, typename OutIt>
void transport_first(InIt src, OutIt dst) {
    *dst = *src;
}
move_iterator Container<T>::mbegin();
move_iterator Container<T>::mend();
transport_first(coll.mbegin(), std::back_inserter(vec));
transport_first(std::mbegin(coll), std::back_inserter(vec));