移动容器的迭代器? [英] Move iterators for containers?

查看:137
本文介绍了移动容器的迭代器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++ 98容器定义了两种迭代器, :: iterator s和 :: const_iterators 。通常,像这样:

C++98 containers defined two kinds of iterator, ::iterators and ::const_iterators. Generally, like this:

struct vec{
   iterator begin();
   const_iterator begin() const;
};

在C ++ 11中,这部分设计似乎没有改变。
问题是,
为了保持一致性和实际目的,添加 :: move_iterator 也是有意义的吗?或者它有点矫枉过正。

In C++11 this part of the design seems to be unchanged. The question is, for consistency and for practical purposes would it make sense to add ::move_iterators as well? or it an overkill.

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

I can imagine that an rvalue container maybe have their elements moved if possible.

class vec{
   iterator begin() &;
   const_iterator begin() const&;
   move_iterator begin() &&;
};

如果我理解正确,可以在简单的情况下实现:

If I understand correctly, it could be implemented like this in simple cases:

auto vec::begin() &&{return std::make_move_iterator(this->begin());}






当然正常的迭代器可以转换为移动迭代器(带有 std :: make_move_iterator ),但动机是通用代码。


Of course a normal iterator can be converted to a move iterator (with std::make_move_iterator), however the motivations is generic code.

例如,使用移动迭代器,这将是根据参数是左值还是右值,可以非常优雅地实现。

For example, with a move iterator this would be very elegantly implemented without conditions depending on whether the argument is an lvalue or an rvalue.

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 开始生成,如何实现。

Note that this code would incur in no unnecessary copies if possible. How can this be implemented without move_iterators generated by begin.

我也意识到这个问题几乎适用于容器的任何访问者,例如 operator [] front() back()

I also realize that this question applies to almost any accessor to the container, for example, operator[], front() and 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中从头开始重新设计。
他们的设计显示了它的年龄。

Perhaps containers should have been redesigned from scratch in C++11. Their design is showing its age.

有一个建议,自动推断出(decl)类型(* this)基本上具有免费的所有相应的begin(和其他成员函数)重载。

There is a proposal, to automatically deduce the (decl)type of (*this) basically having all the corresponding overload of begin (and other member functions) for free.

https://youtu.be/yB4E-SzQPdI?t=4131

推荐答案

STL容器旨在与STL算法结合使用。当前在STL中找到的泛型算法处理迭代器,但您的模板函数 transport_first

STL containers are designed to be used in conjunction with STL algorithms. The generic algorithms currently found in the STL deal with iterators, but your template function 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的一部分。

consists of container-based code, i.e.: it operates on containers rather than on iterators. We may be able to find such container-based algorithms as part of the STL as of C++20 thanks to concepts.

类似STL的方法通用 transport_first 算法实际上是:

The "STL-like approach" to a generic transport_first algorithm would actually be:

template<typename InIt, typename OutIt>
void transport_first(InIt src, OutIt dst) {
    *dst = *src;
}

遵循这种方法(即:迭代器代替容器),当谈到通用代码,是否使用 move_iterator 可以简单地在最顶层通用算法中确定,因为传递的迭代器被进一步复制(即:通过值传递到底层算法)。

Following this approach (i.e.: iterators instead of containers), when it comes to generic code, whether to use move_iterator or not can be simply determined at the "topmost" generic algorithm, since the passed iterators are copied further (i.e.: being passed by value into the "underlying" algorithms).

此外,与上面基于迭代器的 transport_first 不同,STL已满基于迭代器对的算法(例如: std :: copy )来实现范围。这个界面使得 rvalues 上的容器成员函数重载变得很有吸引力,因为已经在其他答案中说明了,那些重载的成员函数将被调用,其中包括未命名的(非 const )容器对象,未命名的容器对象仅限于在单个表达式中使用,通过调用 begin() end()迭代器对 >同一容器对象上的成员函数。

In addition, unlike the iterator-based transport_first above, the STL is full of iterator pair-based algorithms (e.g.: std::copy) to implement ranges. This interface makes overloading those container member functions on rvalues little attractive, because as already stated in this other answer, those overloaded member functions will be called, among others, on unnamed (non-const) container objects, and unnamed container objects are limited to be used in a single expression, hindering the creation of an iterator pair by calling both begin() and end() member functions on the same container object.

容器真正有意义的是拥有新的新成员函数返回相应的 move_iterator 对象:

What would really make sense for containers, is to have fresh new member functions for returning the corresponding move_iterator objects:

move_iterator Container<T>::mbegin();
move_iterator Container<T>::mend();

这只是调用 std :: make_move_iterator ,返回迭代器的成员函数返回的值。成员函数 mbegin()将在基于迭代器的 transport_first 中用作:

This would be just a shortcut for calling std::make_move_iterator with the value returned by the member functions returning a iterator. The member function mbegin() would be used in the iterator-based transport_first as:

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

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

The corresponding function templates std::mbegin() and std::mend() would also make sense:

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

这篇关于移动容器的迭代器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆