c++11 - move 容器的迭代器?

标签 c++11 stl iterator move const-iterator

C++98 容器定义了两种迭代器,::iterator s 和 ::const_iterators .一般来说,像这样:

struct vec{
         iterator begin()      ;
   const_iterator begin() const;
};
在 C++11 中,这部分设计似乎没有改变。
问题是,
为了一致性和实际目的,添加 ::move_iterator 是否有意义?也一样? 或者它是一个矫枉过正。
我可以想象,如果可能的话,右值容器可能会 move 它们的元素。
class vec{
         iterator begin()      &;
   const_iterator begin() const&;
    move_iterator begin()     &&;
};
如果我理解正确,可以在简单的情况下这样实现:
    auto vec::begin() &&{return std::make_move_iterator(this->begin());}

当然,普通迭代器可以转换为 move 迭代器(使用 std::make_move_iterator ),但是动机是通用代码。
例如,使用 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());
}
请注意,如果可能,此代码不会产生不必要的副本。
没有 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&{...}
    };
也许容器应该在 C++11 中从头开始重新设计。
他们的设计正在显示它的时代。

有一个提议,自动推导出 (*this) 的(decl)类型基本上免费拥有 begin (和其他成员函数)的所有相应重载。
https://youtu.be/yB4E-SzQPdI?t=4131

最佳答案

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());
}

由基于容器的代码组成,即:它在容器而不是迭代器上运行。多亏了概念,我们也许能够在 C++20 的 STL 中找到这样的基于容器的算法。

通用 transport_first 算法的“类似 STL 的方法”实际上是:
template<typename InIt, typename OutIt>
void transport_first(InIt src, OutIt dst) {
    *dst = *src;
}

遵循这种方法(即:迭代器而不是容器),当涉及到泛型代码时,是否使用 move_iterator 可以简单地在“最顶层”泛型算法处确定,因为传递的迭代器被进一步复制(即:被传递值到“基础”算法中)。

此外,与上面基于迭代器的 transport_first 不同,STL 充满了基于迭代器对的算法(例如:std::copy)来实现范围。这个接口(interface)使得在右值上重载那些容器成员函数没有什么吸引力,因为正如 this other answer 中已经说明的那样,这些重载的成员函数将在未命名(非 const )容器对象上被调用,并且未命名的容器对象仅限于使用在单个表达式中,通过在同一容器对象上调用 begin()end() 成员函数来阻碍迭代器对的创建。

对于容器来说真正有意义的是拥有新的成员函数来返回相应的 move_iterator 对象:
move_iterator Container<T>::mbegin();
move_iterator Container<T>::mend();

这只是调用 std::make_move_iterator 的快捷方式,成员函数返回的值返回 iterator 。成员函数 mbegin() 将在基于迭代器的 transport_first 中用作:
transport_first(coll.mbegin(), std::back_inserter(vec));

相应的函数模板 std::mbegin()std::mend() 也有意义:
transport_first(std::mbegin(coll), std::back_inserter(vec));

关于c++11 - move 容器的迭代器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48915905/

相关文章:

c++ - 第一个模板类型的模板参数

c++ - 将 std::reference_wrapper<Derived> 视为 std::reference_wrapper<Base> 的最佳方式

C++ - STL - 映射到 int 表

c++ - 使用 std::mutex 实现信号量

c++11 - Const 引用 VS move 语义

c++ - 如何在共享指针中为模板类使用前向声明(在 C++ 中)

c++ - 如何使用标准 STL 算法从 istream 填充 std::vector

c++ - 检查映射是否包含另一个映射中的所有键

c++ - 访问 vector 的内容

c++ - 使用迭代器语法循环 VS 使用生成器语法循环