std::vector元素的销毁顺序

27

我猜这取决于保证是否也适用于原始数组,因为std::vector模拟了数组。但我不知道标准对此的规定。 - Klaim
@Klaim:std::vector仅通过op[]语法模拟数组;这并不意味着有任何元素生命周期的保证。 - Lightness Races in Orbit
3个回答

18

2003:5.3.5/6提到了delete[]:

删除表达式将会调用被删除对象或数组元素的析构函数(如果有的话)。对于数组,元素的销毁顺序是地址递减的顺序(也就是以它们构造完成的相反顺序进行销毁;见12.6.2)。

所以如果你的std::vector对象的分配器使用了delete[],那么它会按照相反的顺序销毁元素。

然而,并没有保证你的std::vector会以这种方式工作(实际上很可能不会),我也找不到任何特定于容器的引用。

事实上,我认为这完全取决于你的分配器,2003:20.1.5(列出了对分配器施加的要求)似乎没有任何相关说明。


7
几乎可以确定的是,std::vector不会使用delete[],因为一个合理的实现需要额外分配但未初始化的空间,而这些空间上的构造函数尚未运行(因此也就不应该执行析构函数)。 - Ben Voigt
2
@BenVoigt:我猜它相当频繁地使用了定位new运算符? - Lightness Races in Orbit
3
它使用 allocator_traits<allocator_type>::constructallocator_traits<allocator_type>::destroy,它们默认情况下分别是放置构造函数和显式析构函数调用的包装器。 - Ben Voigt
@Etienne:但是这样delete[]就不会销毁对象,只有char...所以你无法推断对象如何被销毁。 - Ben Voigt
2
@Tomalak:vector不仅不能保证调用delete[]来删除包含其元素的T类型数组,实际上它是不会这样做的。你无法实现一个分配器类,一次性delete[]整个数组,因为vector需要逐个destroy它们。唯一的出路是“as-if”规则——如果vector使用默认分配器,则我想它可能delete[],但这将取决于该实例的历史记录,因为vector::resize()仍然必须以某种方式实现。 - Steve Jessop
显示剩余8条评论

7
没有对于数组的任何保证,只有当所有元素都按顺序构造并按相反顺序销毁时才能保证。这与全局对象的处理方式有些一致。
另一方面,容器成员可以使用例如“insert”和“erase”成员函数以任意顺序构造和销毁。为了保持一致并按构造的相反顺序销毁元素,这将需要容器记录这些更改的某种日志。显然,这将是昂贵的!
最好的方法是容器析构函数调用“clear()”,它被定义为“erase(begin(), end())”,但我也找不到对此的任何要求。标准仅在表65中说“线性复杂度”。

5
他们的标准保证了原始数组的这一点,但我找不到任何保证容器的内容。
根据C++0x中的[expr.delete](新的措辞):
如果delete-expression的操作数的值不是空指针值,则delete-expression将调用正在删除的对象或数组元素的析构函数(如果有)。 对于数组,元素将按地址递减的顺序销毁(即以其构造函数完成的相反顺序;请参阅12.6.2)。
std :: vector(实际上,标准库中的所有容器,可能不包括std :: array)不使用delete []来销毁元素(它们在每个元素上使用allocator_traits< allocator_type> :: destroy),因此上述保证不适用。 我找不到特定于std :: vector或容器总体而言关于删除顺序的限制。 对于某些容器,这样的保证将非常昂贵(例如,std :: forward_list无法迭代元素以反向删除它们,而std :: map不记住添加对的顺序)。
根据[C ++ 0x措辞]的[container.requirements.general]:
对于受此子条款影响的组件声明allocator_type的组件,存储在这些组件中的对象应使用allocator_traits :: construct函数构造,并使用allocator_traits :: destroy函数(20.6.8.2)进行销毁。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接