C++中对不可拷贝vector元素执行destroy_at/重建操作的风险如何?
结论
你给出的实现存在未定义行为(UB),不是安全操作,针对你的两个疑问具体解释如下:
疑问1:i=0时是否需要vector执行std::launder?
需要,且不止i=0的场景:
- 你手动销毁下标i处的对象并原地重建新对象后,所有指向该旧对象的指针(包括vector内部存储的、用于访问元素的底层指针,以及你之前通过
vec[i]、迭代器等拿到的指向该位置的指针/引用)都无法直接指向新对象,必须经过std::launder处理后才是合法指针。 - 但vector本身不知道你做了原地销毁重建的操作,后续它访问下标i的元素时,还是会用自己内部未经过
std::launder的旧指针计算地址,这本身就会触发UB,和你自己有没有对elem做launder无关。
疑问2:pair含const key的场景销毁重建是否会导致UB?
会,这是更核心的问题:
根据C++标准[basic.life]章节的规定,如果你要在一个已销毁对象的存储地址原地重建新对象,并且希望原来的指针/引用可以正常访问新对象,要求原对象不包含const非静态数据成员、也不包含引用类型的非静态数据成员。
你存储的std::pair<const key, value>里第一个成员是const类型,直接违反了这个要求。哪怕你手动对所有相关指针做了std::launder处理,这种场景下的原地重建操作本质上也是UB。
替代方案
如果你想要实现带const key元素的swap-and-pop,更安全的做法是避免直接在vector内存储带const成员的类型:可以把key的const修饰去掉,只对外暴露不可修改key的接口;或者采用std::vector+std::map的组合结构来同时满足下标访问和key不可变的需求。
内容的提问来源于stack exchange,提问作者skypjack
相关产品推荐
相关产品推荐

