You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

何种C++标准条款判定T构造函数中调用std::vector<T>::clear()的行为未定义?

问题分析:容器操作过程中修改容器导致的未定义行为

考虑以下代码:

#include <string>
#include <vector>

struct Foo;

std::vector<Foo> v;

struct Foo {
    std::string s = std::string(10000, 'x');
    Foo() {}
    Foo(int) { v.clear(); }
};

int main() {
    v.resize(1);  // required, otherwise no double free
    v.reserve(2);  // optional
    v.emplace_back(10);  // causes double free
}

这段代码中,调用v.emplace_back(10)会触发Foo(int)构造函数,而该构造函数会在emplace_back执行完成前调用v.clear()。在Ubuntu 22.04的libstdc++实现中,这会导致双释放:v[0]先被clear()销毁,后续又被v的析构函数销毁。

对应的C++标准条款

该程序的行为属于未定义行为,对应的C标准条款在容器通用要求部分(以C20为例,条款编号为[container.reqmts.general]/15):

如果一个容器操作会修改容器,那么在该操作执行期间修改容器的行为是未定义的。

更具体地说,emplace_back是一个会修改容器的操作(它会向容器中添加新元素,可能改变容器的size等状态)。在emplace_back的执行过程中——也就是构造新Foo对象的阶段——调用v.clear()直接修改了同一个容器,这违反了容器操作的基本约束,导致行为未定义。

为什么即使没显式访问元素也会出问题

你提到“并未访问v的任何元素”,但实际上emplace_back的执行过程已经涉及容器的内部状态管理:

  1. 当调用emplace_back(10)时,容器会先准备好存储新元素的空间(这里已经reserve(2),所以空间足够);
  2. 然后在该空间上构造Foo对象,此时触发Foo(int)构造函数;
  3. 构造函数中调用v.clear(),会销毁容器中已有的所有元素(包括v[0]),并将容器的size重置为0;
  4. 当emplace_back执行完成后,它原本预期要完成新元素的添加,但容器已经被clear()修改,后续容器析构时,会尝试销毁所有“应该存在”的元素,而这些元素已经被clear()销毁过一次,最终导致双释放错误。

这种在容器修改操作的执行过程中嵌套修改容器的行为,完全符合标准中“未定义行为”的判定条件。

内容的提问来源于stack exchange,提问作者yeputons

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 17:42:30