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

在std::vector的emplace_back中嵌套调用emplace_back是否属于UB?

嵌套调用std::vector::emplace_back的未定义行为问题

在向同一std::vector执行emplace_back操作时,若在新元素的构造函数中嵌套调用同一vector的emplace_back添加元素,会出现不同编译器运行结果不一致的情况。以下是最小复现代码:

#include <iostream>
#include <vector>

struct ComplexObject
{
    // for display only
    inline static int cpt {};
    int indice {};

    ComplexObject(std::vector<ComplexObject>& storage, int trick) 
    {
        indice = cpt;
        cpt++;

        if (trick == 0 )
        {
            std::cout << "Creating single Object. Storage size: " << storage.size() << std::endl;
        }
        else
        {
            std::cout << "Creating double Object. Storage size: " << storage.size() << std::endl;
            storage.emplace_back(storage, 0);
            std::cout << "Storage size after double creation : " << storage.size() << std::endl;
        }
    }
};

int main() {
   std::vector<ComplexObject> storage;
    storage.reserve(3); // no realoction

    storage.emplace_back(storage,0);
    std::cout << "_________ size after insert simple : " << storage.size()<<"_________" << std::endl;
    storage.emplace_back(storage,1);
    std::cout << "_________ size after insert double :" << storage.size() << std::endl;

    for (auto& e : storage)
    {
       std::cout << e.indice;
    }
}

预期最后循环输出为012或021,但Clang和GCC运行结果不一致:

Clang输出

Creating single Object. Storage size: 0
_________ size after insert simple : 1_________
Creating double Object. Storage size: 1
Creating single Object. Storage size: 1
Storage size after double creation : 2
_________ size after insert double :2
02

GCC输出

Creating single Object. Storage size: 0
_________ size after insert simple : 1_________
Creating double Object. Storage size: 1
Creating single Object. Storage size: 1
Storage size after double creation : 2
_________ size after insert double :3
020

两者均出现元素被覆盖的情况,且vector的最终大小存在分歧(推测GCC中最后一个0为垃圾内存)。核心问题:这段代码是否属于未定义行为(UB)?若是,哪部分导致?若不是,哪个编译器存在错误?


解答

这段代码确实属于未定义行为,触发原因如下:

根据C++标准,std::vector::emplace_back的执行流程包含三个关键步骤:

  1. 确保容器有足够容量(本例中已通过reserve避免扩容,但步骤依然存在)
  2. 在容器末尾的内存位置构造新元素
  3. 增加容器的size()值

当外层emplace_back正在执行步骤2(即ComplexObject的构造函数运行期间),内层嵌套调用同一个vector的emplace_back,会直接修改容器的状态(完成新元素构造并增加size())。此时外层emplace_back的执行环境已经被破坏:它原本准备构造元素的内存位置,可能被内层操作占用或覆盖,而容器的size()也在未完成外层操作时被修改。

C++标准明确规定:容器的修改操作(如emplace_back)执行期间,容器处于不稳定状态,此时嵌套调用同一容器的修改操作,其行为是未定义的——标准不保证这种场景下的执行结果,因此不同编译器可以自由实现,最终导致输出不一致。

即使调用了reserve避免扩容,也无法解决核心问题,因为UB的根源并非扩容导致的迭代器失效,而是修改操作过程中嵌套修改容器状态的行为违反了标准约束。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 10:55:58