为什么std :: vector的元素需要移动构造函数? [英] Why does std::vector require move-constructors for its elements?

查看:898
本文介绍了为什么std :: vector的元素需要移动构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++ 98指出std :: vector元素应具有复制构造函数.在C ++ 11中,情况已不再如此.相反,元素必须具有移动构造函数.

C++98 stated that std::vector elements should have copy-constructors. In C++11 that's no longer the case. Instead, the elements must have move-constructors.

取决于您对std :: vector的处理方式,您可能确实需要调用复制构造函数或移动构造函数,也可能不需要,但是标准始终只正式要求它们中的一个.为什么?

Depending on what you do with std::vector, you may or may not really need to call the copy- or move-constructor, yet only one of them is always formally required by the standard. Why?

更新:显然,前提不正确.我的困惑来自阅读诸如之类的答案.

Update: Apparently, the premise is incorrect. My confusion stemmed from reading answers such as this.

推荐答案

正如注释中所暗示的,在向量中存储的所有对象上并没有简单的一揽子要求.而是将要求放在特定的操作上.

As implied in the comments, there isn't simply one blanket set of requirements on all objects you store in a vector. Rather, the requirements are placed on specific operations.

尽管要做的许多操作要求对象类型不是MoveConstructible和/或MoveAssignable,但是复制构造和复制分配符合该要求,也就是说,可复制构造是基本上是可构造动作的超集,并且(同样是副本分配与移动分配).

Although a number of operations do require than the object type be MoveConstructible and/or MoveAssignable, copy construction and copy assignment qualify for meeting that requirement--that is, copy constructible is basically a superset of move constructible and (likewise copy assignment vs. move assignment).

相反并非如此.例如,如果您将两个参数构造函数用作向量:

The reverse is not true though. For example, if you use the two argument constructor for a vector:

std::vector<T> vec(n, t);

...那么T必须是可复制构造的(因为它将尝试在向量中创建tn副本,并且通过move构造,它只能创建一个项目).

...then T must be copy constructible (because it's going to attempt to create n copies of t in the vector, and with move construction, it would only be able to create one item).

如果希望将其视为继承层次结构,则可以将copy(assignment | construction)视为派生类,将move(assignment | construction)视为基类,因此可以隐式地将复制替换为move但反之亦然.

If you wanted to look at it as an inheritance hierarchy, you could think of copy(assignment|construction) as a derived class, and move(assignment|construction) as the base class, so you can implicitly substitute copying for moving but not vice versa.

在很多情况下,对list的元素的要求比对vectordeque的元素的要求宽松(对vectordeque的元素的要求几乎总是相同的,我知道的唯一例外(感谢@yakk)是emplace_back,它要求向量使用MoveConstructible,否则需要EmplaceConstructible,以及下面列出的下一项-但请注意其警告).

There are quite a few cases where requirements on elements of a list are looser than those on elements of a vector or deque (requirements on elements of vector and deque are nearly always identical, the sole exceptions of which I'm aware (thanks @yakk) being emplace_back, which requires MoveConstructible for vector, EmplaceConstructible otherwise and the next item listed below--but note its caveat).

如果使用std::vector<x> myvector(i, j);myvector.assign(i, j);(其中ij是迭代器),则对T的要求取决于迭代器的类-如果它们是转发迭代器,则仅T必须是EmplaceConstructible,否则T必须是MoveConstructible.注意:尽管确实反映了标准中的当前用词,但根据

If you use std::vector<x> myvector(i, j); or myvector.assign(i, j);, (where i and j are iterators) then the requirements on T depend on the class of the iterators--if they're forward iterators, then T only needs to be EmplaceConstructible, otherwise T must be MoveConstructible. Caveat: although this does reflect the current wording in the standard, according to LWG 2266 the restrictions for the constructor are incorrect: they should apply regardless of the iterator category, and apply equally to vector and deque. Some future version of the standard will reflect that, but in real use that's how things already are.

如果有人在乎这是为什么,以及为什么对非转发迭代器进行特殊处理:问题是使用std::istream_iterator之类的东西,就无法提前知道迭代器范围可能有多少个项目参考.使用随机访问迭代器之类的东西,它可以简单地使用j - i来确定项目数,留出足够的空间并适当地插入.为了有效使用istream_iterator,它们通常将数据复制到当前集合的末尾,然后在将整个范围复制/移动到集合中之后,使用rotate将它们移动到所需位置.使用rotate支持额外的要求.

In case anybody cares about why that is, and why the special treatment for non-forward iterators: the problem is that with something like an std::istream_iterator, there's no way to know ahead of time how many items an iterator range might refer to. With something like random-access iterators, it can simply use j - i to determine the number of items, make that much space, and insert appropriately. To work efficiently with istream_iterators, they normally copy the data to the end of the current collection, then after the entire range has been copied/moved into the collection, use rotate to move them to the desired location. The extra requirement(s) support using rotate.

insert有一个变体,如果您要插入到vectordeque中,则除了(Move | Copy)(Constructible | Assignable)外,还要求元素可交换.与上面给出的类似:对于insert的这种变体,元素实际上被插入到一个位置,然后四处移动以使其到达它们所属的位置.

There's one variant of insert that requires elements to be swappable in addition to (Move|Copy)(Constructible|Assignable) if you're doing the insert into a vector or deque (the reasoning here is similar to that given above: for this variant of insert, elements are actually inserted in one place, and then moved around to get them to where they belong).

这篇关于为什么std :: vector的元素需要移动构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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