std::vector<T> littleVector(1);
std::vector<T> bigVector;
bigVector.reserve(100);
bigVector = littleVector;
是否标准说bigVector
仍然有100个元素保留?或者如果我想要记忆重新分配,我会不会觉得?也许它在STL实现中有所不同。
这是之前讨论的here,但没有给出标准参考。
std::vector<T> littleVector(1);
std::vector<T> bigVector;
bigVector.reserve(100);
bigVector = littleVector;
是否标准说bigVector
仍然有100个元素保留?或者如果我想要记忆重新分配,我会不会觉得?也许它在STL实现中有所不同。
这是之前讨论的here,但没有给出标准参考。
不幸的是,该标准在分配器感知的序列容器分配上没有详细说明行为,实际上严格来说是不一致的。
我们知道(从表28和从23.2.1p7)如果allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value
是true
那么分配器在复制分配时被替换。另外,从表96和99,我们发现拷贝赋值的复杂是线性,并且后条件上操作a = t
是a == 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()
之后发生的插入过程中不发生重新分配,直到插入将使向量的大小大于capacity()
的值。
如果我们取library DR341为指导,以读取所述标准:
然而,23.3.6.3措辞[vector.capacity]段落5防止一个向量的容量减小,承接调用reserve()。这使成语无效,因为swap()因此被阻止减小容量。 [...]
DR341通过添加段落分解为23.3.6.3:
void swap(vector<T,Allocator>& x);
7 - 影响:交流的内容,并与中x
的*this
capacity()
。
8 - 复杂性:恒定时间。
结论是,从图书馆委员会的角度来看,如果在23.3.6.3中提到,操作只修改capacity()
。复制分配未在23.3.6.3中提及,因此不会修改capacity()
。 (移动分配有相同的问题,特别是考虑到所提出的决议Library DR2321)
显然,这是在标准的缺陷,如拷贝赋值传播不平等分配器必须结果重新分配,矛盾23.3.6.3p5。
我们可以期待,并希望这一缺陷,以有利于解决:
capacity()
;capacity()
关于分配器修改副本分配;capacity()
关于非分配器传播移动分配;capacity()
。但是,在目前的情况下,直到明确这一点,您最好不要依赖任何特定的行为。幸运的是,这是保证不降低capacity()
一个简单的解决方法:
bigVector.assign(littleVector.begin(), littleVector.end());
容量备注限制了插入的行为。可以说容器分配不属于插入类别。 –
@BenVoigt序列容器复制分配被指定为需要'CopyAssignable'。看起来非常清楚,如果初始容量不足,非分配器修改副本分配必须导致重新分配。 – ecatmur
我同意。但我不知道一个僧侣是否会把这个操作称为“插入”并应用上述规则。 –
这取决于分配器特征。
下面是摘录自http://en.cppreference.com/w/cpp/container/vector/operator%3D:
如果性病:: allocator_traits :: propagate_on_container_copy_assignment()为真,则目标分配器由源分配的副本代替。如果目标分配器和源分配器之间的比较不相等,则使用目标(* this)分配器来释放内存,然后使用其他分配器在复制元素之前分配它(自C++ 11以来)
基本上,存储器被重新分配与所述新的分配器,如果分配器是不相容(如果他们不能解除分配每个-其它的存储器。
它不应该矢量实现之间关系,但是分配器实现之间(这使得有义)
您是否对该声明有规范性参考(即从标准)? – ecatmur
尽管这是正确的,但它并没有回答分配器是否相同时也会发生释放,或者不在容器复制分配上传播。 –
@ecatmur:23.2.1p7讨论了分配器替换。分配器更换的时刻是允许容器最后一次使用旧分配器的时间;所有未来的操作都是根据替换分配器来定义的。因此,此时它必须释放其旧缓冲区。 –
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()
的一般不变性的能力。因此,分配后的容量值是未指定的,只要分配器需求得到保留,容器就可以随意实现分配。
在一般情况下,你会发现,实现的行为,使得
当然,移动分配是一个不同的故事。由于通常通过窃取源存储来实施,因此容量也会被采用。
@davidhigh:是的,它会回答这个问题对我特别的编译器和STL实现,但我也可以回答这样的问题“是什么'I =我以类似的方式“做”。 –
非常好的问题,+1。在标准中我找不到任何直接的东西;尽管如此,分配器需求的黑暗魔力可能会产生一些后果。 – Angew
我知道如果源的分配器不同于目标,它会转储整个目标缓冲区。我不能评论它是否尊重当前的保留,如果他们在不参考标准的情况下使用* same * allocator。 (很好的问题,顺便说一句)。 – WhozCraig