vector分配是否使`reserve`无效?

假设我写了

std::vector<T> littleVector(1); std::vector<T> bigVector; bigVector.reserve(100); bigVector = littleVector; 

标准是否说bigVector仍然有100个元素保留? 或者,如果我要push_back 99个元素,我会经历内存重新分配吗? 也许它在STL实现之间甚至有所不同。

这是以前在这里讨论的,但没有给出标准参考。

不幸的是,这个标准在分配器感知的序列容器分配上没有详细说明行为,事实上严格来说是不一致的。

我们知道(从表28和23.2.1p7),如果allocator_traits<allocator_type>::propagate_on_container_copy_assignment::valuetrue那么分配器在复制分配上被replace。 进一步,从表96和表99中我们发现复制分配的复杂性线性的 ,并且操作后条件 a = ta == t ,即(表96), distance(a.begin(), a.end()) == distance(t.begin(), t.end()) && equal(a.begin(), a.end(), t.begin()) 。 从复制分配后的23.2.1p7开始,如果分配器传播,则a.get_allocator() == t.get_allocator()

关于媒介能力,23.3.6.3 [vector.capacity]具有:

5 – 备注:重新分配将使所有引用序列中的元素的引用,指针和迭代器失效。 保证在调用reserve()之前发生的插入过程中不发生重新分配,直到插入将使vector的大小大于capacity()的值。

如果我们以图书馆DR341作为阅读标准的指南:

然而,23.3.6.3 [vector.capacity]第5段的措辞阻止了在调用reserve()之后向量的容量减less。 这使成语无效,因为防止了swap()减小容量。 […]

DR341通过在23.3.6.3中添加段落得到解决:

void swap(vector<T,Allocator>& x);
7 – 效果:*this的内容和capacity()x的内容和capacity()交换。
8 – 复杂性:时间不变。

结论是,从图书馆委员会的angular度来看,如果在23.3.6.3中提到的话,操作只能修改capacity() 。 复制分配在23.3.6.3中没有提到,因此不修改capacity() 。 (移动分配有相同的问题,特别是考虑到图书馆DR2321提议的决议。)

显然,这是标准中的一个缺陷,因为复制分配传播不平等的分配者必须导致重新分配,与23.3.6.3p5相矛盾。

我们可以期待并希望这个缺陷得到解决,有利于:

  • 非分配器修改拷贝分配的非减lesscapacity() ;
  • 未指定capacity()分配器修改副本分配;
  • 非分配器传播移动分配的非减lesscapacity() ;
  • 分配器传播移动分配上的源容器capacity()

但是,在目前的情况下,直到这个问题得到澄清,你将不会依赖任何特定的行为。 幸运的是,有一个简单的解决方法,保证不会减lesscapacity()

 bigVector.assign(littleVector.begin(), littleVector.end()); 

对于标准容器, operator=的唯一要求是之后的src == dst ,如表96(23.2,一般容器要求)中所规定的那样。 而且,同一个表格指定了operator ==的含义:

 distance(lhs.begin(), lhs.end()) == distance(rhs.begin(), rhs.end()) // same size && equal(lhs.begin(), lhs.end(), rhs.begin()) // element-wise equivalent 

请注意,这不包括任何方式的容量。 标准的任何其他部分也没有提到capacity() >= size()的一般不变性。 因此,赋值后的容量值是未指定的,只要保留了分配器的要求,容器就可以自由地实现赋值。


一般来说,你会发现实现的行为如此

  • 如果分配者比较相等并且dst具有足够的容量,则将保留其旧存储器,
  • 否则会为新元素分配足够的存储空间
  • 在任何情况下都不会在乎src的能力。

当然,转移是一个不同的故事。 由于一般通过窃取源存储来实施,所以容量也会被采用。

这取决于分配器的特点。

以下是http://en.cppreference.com/w/cpp/container/vector/operator%3D的摘录:;

如果std :: allocator_traits :: propagate_on_container_copy_assignment()为true,则目标分配器将被源分配器的副本replace。 如果目标和源分配器不相等,则使用目标(* this)分配器来解除分配内存,然后使用其他分配器在复制元素之前分配它(自C ++ 11以来)

基本上,如果分配器不兼容(如果它们不能释放对方的内存,则使用新的分配器重新分配内存。

在vector实现之间,而不是在分配器实现之间(这是有道理的)。