C ++ 98声明std :: vector元素应该有copy-constructors。在C ++ 11中,情况不再如此。相反,元素必须具有move-constructors。
根据你对std :: vector的处理方式,你可能真的需要或者可能不需要调用copy-或move-构造函数,但标准中始终只需要其中一个。为什么呢?
更新:显然,前提是不正确的。我的困惑源于阅读this等答案。
答案 0 :(得分:5)
正如评论中所暗示的那样,对于存储在向量中的所有对象,并不是简单的一组要求。相反,要求是针对特定的操作。
虽然许多操作做需要的对象类型为MoveConstructible
和/或MoveAssignable
,但复制构造和副本分配符合满足该要求的要求 - 即,copy constructible基本上是移动可构造的超集(同样是复制赋值与移动赋值)。
但事实并非如此。例如,如果对向量使用两个参数构造函数:
std::vector<T> vec(n, t);
...然后T
必须是可复制的(因为它将尝试在向量中创建n
个t
个副本,并且通过移动构造,它只能够创建一个项目。)
如果要将其视为继承层次结构,可以将copy(赋值|构造)视为派生类,并将(赋值|构造)作为基类移动,因此可以隐式替换复制以进行移动但反之亦然。
在很多情况下,list
元素的要求比vector
或deque
元素的要求更宽松(对vector
元素的要求和deque
几乎总是相同的,唯一的例外是我(感谢@yakk)是emplace_back
,这需要MoveConstructible用于vector,EmplaceConstructible以及下面列出的下一个项目 - 但请注意需要注意的)。
如果使用std::vector<x> myvector(i, j);
或myvector.assign(i, j);
,(其中i
和j
是迭代器),则对T的要求取决于迭代器的类 - 如果它们'重新转发迭代器,然后T只需要是EmplaceConstructible,否则T必须是MoveConstructible。警告:虽然这确实反映了标准中的当前措辞,但根据LWG 2266,构造函数的限制是不正确的:它们应该适用于迭代器类别,并且同样适用于vector和deque。该标准的某些未来版本将反映出这一点,但实际使用的情况就是这样。
如果有人关心为什么会这样,以及为什么对非前向迭代器进行特殊处理:问题是像std::istream_iterator
这样的问题,就没有办法提前知道迭代器有多少项范围可能是指。使用随机访问迭代器之类的东西,它可以简单地使用j - i
来确定项目数,创建那么多空间并适当插入。为了有效地使用istream_iterator
s,它们通常会将数据复制到当前集合的末尾,然后在将整个范围复制/移动到集合中之后,使用rotate
将它们移动到所需的集合中地点。使用rotate
的额外要求支持。
如果你要插入insert
或{{1},那么vector
的一个变体除了(Move | Copy)(Constructible | Assignable)之外还需要元素可以交换。 (这里的推理类似于上面给出的推理:对于deque
的这个变体,元素实际上插在一个地方,然后四处移动以使它们到达它们所属的位置。
答案 1 :(得分:0)
它在哪里声明元素必须在C ++ 11中具有std :: vector的move-constructors?像这样的规则会破坏很多现有代码,因为现有的类不一定具有移动构造函数。您可能需要复制构造函数,或者如果您没有复制构造函数,那么您至少需要一个移动构造函数。