为什么std :: vector需要移动构造函数用于其元素?

Max*_*axB 1 c++ stl vector move-semantics c++11

C++ 98声明std :: vector元素应该有copy-constructors.在C++ 11中,情况已不再如此.相反,元素必须具有移动构造函数.

根据你对std :: vector的处理方式,你可能真的需要或者可能不需要调用copy-或move-构造函数,但标准中始终只需要其中一个.为什么?

更新:显然,前提是不正确的.我的困惑从阅读的答案,如朵朵.

Jer*_*fin 5

正如评论中暗示的那样,对于存储在向量中的所有对象,并不是简单的一组要求.相反,要求是针对特定的操作.

虽然许多操作确实需要比对象类型更多MoveConstructible和/或MoveAssignable,但复制构造和复制分配有资格满足该要求 - 也就是说,复制构造基本上是移动可构造的超集和(同样复制分配与移动分配) .

但事实并非如此.例如,如果对向量使用两个参数构造函数:

std::vector<T> vec(n, t);
Run Code Online (Sandbox Code Playgroud)

...然后T必须是可复制的(因为它将尝试在向量中创建n副本t,并且通过移动构造,它只能创建一个项目).

如果要将其视为继承层次结构,可以将copy(赋值|构造)视为派生类,并将(赋值|构造)作为基类移动,因此可以隐式地将复制替换为移动而不是副本反之亦然.

有相当多的情况下,在一个要素的要求list比对的元素宽松vectordeque上的元素(要求vectordeque几乎总是相同的,其中我所知道的唯一的例外(感谢@yakk)是emplace_back,这需要MoveConstructible for vector,EmplaceConstructible否则以及下面列出的下一个项目 - 但请注意其警告).

如果你使用std::vector<x> myvector(i, j);or myvector.assign(i, j);,(where ijis iterators)那么对T的要求取决于迭代器的类 - 如果它们是前向迭代器,那么T只需要是EmplaceConstructible,否则T必须是MoveConstructible.警告:虽然这确实反映了标准中的当前措辞,但根据LWG 2266,对构造函数的限制是不正确的:它们应该适用于迭代器类别,并且同样适用于vector和deque.该标准的某些未来版本将反映出这一点,但在实际使用中,事情已经如此.

如果有人关心为什么会这样,以及为什么对非前向迭代器进行特殊处理:问题是如果有类似的东西std::istream_iterator,则无法提前知道迭代器范围可能引用的项目数.使用随机访问迭代器之类的东西,它可以简单地用于j - i确定项目数量,创建那么多空间并适当插入.为了有效地使用istream_iterators,它们通常将数据复制到当前集合的末尾,然后在将整个范围复制/移动到集合中之后,使用rotate它们将它们移动到所需位置.额外的要求支持使用rotate.

insert除了(Move | Copy)(可构造|可分配)之外,还有一个变量要求元素可以交换,如果你正在插入一个vectordeque(这里的推理类似于上面给出的那个:对于这个变体insert,元素实际上是插在一个地方,然后四处移动,让他们到达他们所属的地方).