假设我写了
std::vector<T> littleVector(1);
std::vector<T> bigVector;
bigVector.reserve(100);
bigVector = littleVector;
标准是否表示bigVector
仍会保留100个元素?或者,如果我要push_back
99个元素,我会经历内存重新分配吗?也许它甚至在STL实现之间也有所不同。
之前曾讨论here,但未提供标准参考资料。
答案 0 :(得分:19)
不幸的是,标准规定了分配器识别序列容器分配的行为,严格来说确实是不一致的。
我们知道(从表28和23.2.1p7),如果allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value
是true
,则在复制分配时替换分配器。此外,从表96和99中我们发现复制赋值的复杂度是线性,而后置条件在操作{{1}上是a = t
,即(表96)a == t
。从23.2.1p7开始,在复制分配后,如果分配器传播,则distance(a.begin(), a.end()) == distance(t.begin(), t.end()) && equal(a.begin(), a.end(), t.begin())
。
关于载体容量,23.3.6.3 [vector.capacity] 具有:
5 - 备注:重新分配使引用序列中元素的所有引用,指针和迭代器无效。保证在调用
a.get_allocator() == t.get_allocator()
之后插入期间不会重新分配,直到插入使向量的大小大于reserve()
的值为止。
如果我们以library DR341作为阅读标准的指南:
然而,在调用reserve()之后,23.3.6.3 [vector.capacity]第5段的措辞阻止了向量的容量减少。这使成语无效,因为防止了swap()减少了容量。 [...]
通过在23.3.6.3中添加段落来解决DR341:
capacity()
7 - 效果:将void swap(vector<T,Allocator>& x);
的内容和capacity()
与*this
的内容进行交换。
8 - 复杂性:恒定时间。
结论是,从图书馆委员会的角度来看,如果在23.3.6.3中提到,操作只会修改x
。 23.3.6.3中未提及复制分配,因此不会修改capacity()
。 (移动分配具有相同的问题,特别是考虑到Library DR2321的建议解决方案。)
显然,这是标准中的缺陷,因为传播不等分配器的复制分配必须导致重新分配,与23.3.6.3p5相矛盾。
我们可以期待并希望这个缺陷得到解决,有利于:
capacity()
; capacity()
分配器修改副本分配; capacity()
; capacity()
关于分配器传播的移动分配。然而,在目前的情况下,在澄清之前,你最好不要依赖任何特定的行为。幸运的是,有一个简单的解决方法可以保证不会减少capacity()
:
capacity()
答案 1 :(得分:9)
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()
的一般不变量的能力。因此,未指定赋值后的容量值,只要保留分配器要求,容器就可以自由地以任何方式实现赋值。
通常,您会发现实现行为
当然,移动任务是另一回事。由于它通常是通过窃取源存储来实现的,因此也将采用容量。
答案 2 :(得分:6)
这取决于分配器特征。
此处摘录自http://en.cppreference.com/w/cpp/container/vector/operator%3D:
如果std :: allocator_traits :: propagate_on_container_copy_assignment()为true,则目标分配器将替换为源分配器的副本。如果目标和源分配器不比较相等,则使用目标(* this)分配器来释放内存,然后在复制元素之前使用其他分配器来分配它。(自C ++ 11起)
基本上,如果分配器不兼容(如果它们不能释放彼此的内存,则会使用新分配器重新分配内存。
它不应该在向量实现之间,而是在分配器实现之间(这是有意义的)。