为什么C++捕获抛出的异常指针时,what()输出内容与预期不一致?
问题根本原因
你抛出的是栈上局部对象的指针,属于未定义行为,两种测试结果的差异只是未定义行为的不同表现而已。
第一个bad_exception测试现象解释
try块内定义的bad_exception e2是栈内存局部变量,作用域仅限于try块内部。- 执行
throw &e2触发栈展开逻辑时,会先销毁try块内所有局部对象,e2的析构函数会被调用,其内部维护的what()返回的字符串资源已经被清理。 - 你在
catch块拿到的指针地址虽然和原地址一致,但指向的是已经被回收的无效内存,调用ex->what()属于野指针访问,因此输出Unknown exception。
第二个自定义类测试"正常"的原因
这只是未定义行为的巧合,完全不具备可复现性和可靠性:
- 你自定义的
A类是简单结构,默认析构函数没有任何清理内存的逻辑,对象销毁时不会主动覆盖内存内容。 - 测试场景下栈展开后,原对象所在的栈内存还没有被其他操作覆盖,所以你碰巧能读到原来的字符串内容。
- 只要调整编译优化等级、增加局部变量、更换运行环境,大概率会出现乱码、程序崩溃等异常结果。
正确的C++异常抛出实践
C++标准推荐直接抛出异常对象,用引用捕获,完全避免生命周期问题:
try { bad_exception e2 = bad_exception(); cout << e2.what() << endl; cout << &e2 << endl; throw e2; // 抛出对象,异常机制会自动拷贝生成一个生命周期持续到catch结束的异常对象 } catch (const bad_exception& ex) { // 用常量引用捕获,无额外拷贝,也不用担心生命周期 cout << &ex << endl; cout << ex.what() << endl; }
如果一定要抛出指针,必须抛出堆上动态分配的对象指针,且在catch块用完后手动释放,这种方式非常不推荐,极易造成内存泄漏:
try { bad_exception* e2 = new bad_exception(); cout << e2->what() << endl; cout << e2 << endl; throw e2; } catch (bad_exception* ex) { cout << ex << endl; cout << ex->what() << endl; delete ex; // 必须手动释放,否则内存泄漏 }
内容的提问来源于stack exchange,提问作者irous
相关产品推荐
相关产品推荐

