首页 > 解决方案 > 为什么在按值捕获异常时将异常对象移动到 catch 子句对象不标准化,以防它没有被忽略?

问题描述

在 throw-expression 中,如果编译器无法执行复制省略但满足或将满足复制省略的条件,除非源是函数参数,编译器将尝试使用移动构造函数,即使对象由一个左值;

在 catch 子句中,允许以下情况:当参数与抛出的异常对象具有相同类型(忽略 cv 限定)时,省略异常对象的副本,并且 catch 子句的主体直接访问异常对象,好像被引用捕获了一样。如果除了跳过复制构造函数和 catch 子句参数的析构函数之外,此类复制省略会更改程序的可观察行为(例如,如果修改了 catch 子句参数,并且异常对象被重新抛出),则禁用此功能扔)。

在我看来,如果满足此复制省略的条件,则执行移动到 catch 子句参数将是一个合理的解决方案,但编译器无法执行。

因为它只适用于复制省略是安全的情况,所以它也是完全安全的(例如,不妨碍重新抛出异常的最佳实现)。

为什么不是这样?

标签: c++exception

解决方案


throw-expression 中的复制省略与任何其他功能一样,需要在可用之前实现。

移动本身(无论例外)是该语言的必备功能,不支持此功能的成本将是不可原谅的。

应用这个已经存在的特性,在 throw-expression 中以指定的方式移动比实现复制省略要容易得多。

指定的条件对于移动是很自然的,编译器工程师和编译器在运行时执行它都不需要太多额外的工作。

但是在那里实现复制省略需要工程师进行更多的额外工作,并且使编译算法更加复杂。

因此,编译器可以通过在某些或所有情况下不支持某些复制省略的成本而变得更简单。


在 catch 子句中,复制省略的唯一困难是满足条件,复制省略本身在此处可以很简单地实现。复制省略和移到那里的条件仍然相同,实施难度也大致相同。

但是复制省略显然比移动更有效。

所以没有理由让编译器工程师和编译器加载移动特性。


推荐阅读