向量复制/移动分配时底层存储会发生什么?

对于std :: vector的复制分配,当源的大小小于目标容量时,是否允许重新分配存储空间和容量的缩小? 还是保证重新分配/收缩不会发生(即始终尊重先前的准备金())?

另一方面,如果来源的规模大于目的地的容量并进行重新分配,是否要求重新分配尊重来源的容量(例如,目的地的新容量应不小于来源的容量,或者甚至要求它们是一样的)? 或者重新分配只是根据新的规模完成它的工作而不考虑源的容量?

至于移动分配,我认为不会进行存储重新分配(尽管我没有找到标准中的相关部分),那么这是否意味着目的地的新容量的价值将与源的旧容量完全相同? 我可以期待v = vector<T>{};vector<T>{}.swap(v);具有相同的效果vector<T>{}.swap(v);

我想这些答案被埋在标准的某个地方,但我没有找到它们。 (如果C ++ 11和C ++ 03的情况不同,我想知道两者的不同要求。)

PS:对于上述问题的任何答案,std :: string是否相同(仅在C ++ 11中表示连续存储并且没有COW,C ++ 03字符串不在雷达中)?


std::vector<T,A>( std::vector<T,A>&& )

这保证是恒定的时间(N3797表99 X u(rv) )。

我不知道如何在不将指针移动到缓冲区的情况下在不变的时间内移动任意大小的矢量。 如果这(没有办法)是真的,那么构造的向量必须具有至少与源缓冲区一样大的缓冲区。 然而,标准中没有规定vector需要高效的措词:右手vector可以将其容量减小到大于或等于其size任何值:后置条件仅仅是元素是相同的。 从理论上讲,如果右手边vector具有编译器为了任何原因而选择公开的“隐藏能力”(比如说月亮的相位),那么它甚至可以是更大的容量。

在N3797标准中,任何容器上的capacity上限都没有限制。 符合的实现可以使所有的std::vector具有至少200万个元素的容量(禁止allocator失败 - 可以用来强制容量为0 ),没有操作能够将该值减少到200万以下。 ( shrink_to_fit只是一个建议,而std::vector<T,A>().swap(x)可以创建一个200万容量的vector并交换它。

由于上述内容多为负面形式,所以我可以说的就是搜索每个提及vectorallocatorallocatecapacity 。 在任何时候都不能用capacity上限来描述capacity 。 在空的std::vector构造函数中,对allocator额外调用没有任何限制(除了异常安全性)(如果allocator失败,您可能必须保持大小0和容量0,但将该状态提取到任何不会执行的操作使用相同的allocator是具有挑战性的)。


至于复制分配和移动分配,复制分配不能保证超出最基本的capacity() >= size()capacity() >= size() )。

对于移动分配,取决于如何适用:

23.2.1 [container.requirements.general] / 10

除非另有规定(明确地或通过用其他函数定义函数),调用容器成员函数或将容器作为参数传递给库函数不应使迭代器失效或更改该容器内的对象的值。

表96和表99中的a = rv (又名std::vector<T,A>& operator=(std::vector<T,A>&&) )情况是我们关心的问题。 既没有提到rv中包含的值被销毁,也没有提到它们的迭代器失效。 因此,在23.2.1 / 10下迭代器不会失效。

但是,这并不要求缓冲区被移动。 缓冲区从rhs移动到lhs,或者它在rhs vector保持不变。 表99提到了这种情况,当它说lhs项可以被移动分配给(这是std::array可以工作的唯一方式)。

由于std::array没有别的选择,只能移动元素,而std::vector不提供关于移动缓冲区的进一步保证,缓冲区不必移动。 但是,移动缓冲区似乎是一个合法的实现。


在实践中, std::vector<T,A>( std::vector<T,A> const& )将执行右侧内容的副本到左侧,并且在每个实现中,我已经检查了左手侧的capacity等于所得vectorsize 。 同样, std::vector<T,A>( ForwardIterator, ForwardIterator )将产生一个恰好适合其输入的vector

请注意, std::vector<T,A>::operator=(std::vector<T,A>&&)的复杂性保持线性。


我在标准中没有发现任何可以将矢量分配给具有足够容量以降低容量的矢量。 如果我在赋值之前做了reserve ,我保证迭代器不会因重新分配而失效,只要向量永远不会超过我保留的容量。

移动分配的问题是特别的。 似乎没有任何特殊情况允许它使迭代器失效(除非源代码大于目标的容量),但是这样做会使转移赋值的目标失败。 我怀疑这是标准中的缺陷。

编辑:

在表96中,对于a = rv (其中a是一个容器, rv是同一类型容器的非常量r值),该标准给出了线性复杂度,并且表示“所有的元素a a要么被分配到要么被销毁“。 显然,该标准的目的是为了不减少容量; 移动的执行时间优势仅适用于单个元素,而不适用于容器本身。


为了回答你的PS:至少对于std::string ,你不能认为字符串的处理类似于对字符向量的处理。

COW(写时复制)不是实现字符串的必需条件,并不是所有的库实现都这样做。

链接地址: http://www.djcxy.com/p/91711.html

上一篇: What happens to the underlying storage upon vector's copy/move assignment?

下一篇: C++ : Reduce reserved space with std::vector::reserve