C++异常对象作用域疑问:为何未出现预期的副本行为?
关于C++异常对象拷贝与类型转换的问题解答
咱们来逐个拆解你遇到的两个疑问:
疑问1:为什么只看到1次拷贝,而非预期的2次?
Aj的说法在无编译器优化的早期C++标准里是成立的,但现代编译器会通过**复制消除(Copy Elision)**优化掉一次冗余拷贝:
- 执行
throw Some_error {1};时,首先会创建一个临时Some_error对象(对应输出里的Some_error(1))。 - 早期规则中,这个临时对象会先拷贝到专门的异常存储区域(第一次拷贝),再从该区域拷贝到catch块的参数
e(第二次拷贝)。 - 但C++11及以后的标准允许编译器直接用临时对象初始化catch的参数,跳过中间的异常存储对象拷贝,所以你只看到一次拷贝构造的调用(
Some_error(copy::1.1))。
如果想验证这个优化,可以给g++加上-fno-elide-constructors参数禁用复制消除,此时就能看到两次拷贝构造的输出。
疑问2:拷贝后的err_code是1.1,但get_code输出1?
这是类型转换截断导致的问题:
- 你的
err_code是float类型,拷贝构造后的值确实是1.1。 - 但
get_code()函数的返回类型是int,当float类型的1.1转换为int时,会被截断为整数部分1,所以最终输出就是1。
只需要把get_code()的返回类型改成float,就能看到预期的1.1输出:
float get_code() const { return err_code; }
补充:catch使用引用的情况
当你把catch改为catch(Some_error& e)时,catch参数直接引用异常对象,不会触发拷贝构造函数:
- 没有拷贝输出,直接使用原始的异常对象(err_code为1)。
get_code()返回int类型的1,和预期完全一致。
内容的提问来源于stack exchange,提问作者chetzacoalt
相关产品推荐
相关产品推荐

