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

当抛出已有异常时构造函数抛出新异常,为何未调用std::terminate()?

解答

首先明确C++标准中std::terminate()的触发条件:只有当同时存在两个处于活跃状态的未捕获异常时,才会调用该函数终止程序。最常见的触发场景就是异常栈展开阶段(已抛出一个异常,正在向上查找catch块、销毁栈上局部对象的阶段),又有新的异常从栈展开调用的析构函数中抛出且未被处理。

你提到的「抛出异常的过程中,异常对象的构造/拷贝/移动函数抛出新异常」的场景,根本不会产生两个同时活跃的异常,自然不会触发终止,核心逻辑如下:

  • 抛出异常的第一步是构造要抛出的异常对象,这个操作发生在栈展开启动之前。如果构造异常对象的过程中抛出了新异常,那么原本要抛出的旧异常根本没有完成初始化、也没有进入抛出流程,全程只有新抛出的这一个异常处于活跃状态,异常处理机制会正常处理这个新异常。

举个可运行的验证示例:

#include <iostream>
#include <stdexcept>

struct FaultyException {
    FaultyException() {
        // 构造自身时抛出另一个异常
        throw std::runtime_error("FaultyException构造失败");
    }
};

int main() {
    try {
        throw FaultyException();
    } catch (const std::runtime_error& e) {
        std::cout << "成功捕获异常: " << e.what() << std::endl;
    }
    return 0;
}

上述代码可以正常运行并捕获到构造阶段抛出的异常,不会触发std::terminate()。

容易混淆的终止场景对比

只有当栈展开已经启动后再抛新异常才会触发终止,示例如下:

#include <iostream>
#include <stdexcept>

struct BadFoo {
    ~BadFoo() {
        // 栈展开阶段调用析构时抛新异常
        throw std::runtime_error("析构函数抛出异常");
    }
};

int main() {
    try {
        BadFoo f;
        throw std::runtime_error("第一个异常"); // 抛出后进入栈展开,调用f的析构触发第二个异常
    } catch (const std::runtime_error& e) {
        // 永远无法进入该分支,程序会直接终止
        std::cout << e.what() << std::endl;
    }
    return 0;
}

这个场景下确实存在两个同时活跃的异常,符合std::terminate()的触发条件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 11:06:02