为什么标准不允许通过引用捕获不完整的异常类型?
Why is catching incomplete exception types by reference disallowed by the standard?
来自 C++17 标准(草案(,18.3.1:
[...]例外声明不应表示指向不完整类型的指针或引用 [...]
不允许通过引用捕获不完整类型背后的原因是什么?
如果函数参数是通过引用传递的,则仅当函数实际访问收到的对象时才需要完整类型,但它可以愉快地将参数传递给另一个函数,而无需了解该类型。
我不明白为什么这应该与异常不同 - 异常数据本身可能驻留在任何适当的位置,并且在我们找到引用的(展开到处理程序(堆栈上。好。如果处理程序现在可以仅从异常类型中拖动足够的信息,为什么它需要了解完整的定义?
那么我错过了什么?
struct Alice;
struct Bob;
int main() {
try {
throwAlice(); // extern
} catch (Bob&) {
return 0;
}
return 1;
}
以下程序返回什么? 0 或 1 还是鼻魔?好吧,这取决于Alice
继承Bob
.
若要处理异常捕获机制,编译器必须在编译时具有该信息。Bob
应该是一个完整的类型。
原因解释在:
[except.handle]/15
由异常声明声明的变量,类型
cv T
或cv T&
[YSC: 这里,cv T& = Bob&
],从类型 E [YSC: 这里,E = Alice
] 的异常对象初始化,如下所示:
- 如果
T
是E
的基类,则变量从异常对象的相应基类子对象进行复制初始化;- 否则,变量将从异常对象进行复制初始化。
这确认编译器需要在编译时知道Bob
是否继承自Alice
:Bob
必须是完整的类型。
根据 VTT 对该问题的评论(不幸的是,在此期间被删除了"依赖于 RTTI 的异常处理"(以及从 YSC 的回答中得出的基本思想:
异常在运行时引发,异常对象放置在某个(在此范围内,但(明确定义的位置。
如果现在要捕获异常,我们还需要在运行时确定是否有任何异常处理程序与当前抛出的异常匹配,即像这样的代码:
try { throw e; }
catch(E1&) { /*...*/ }
catch(E2&) { /*...*/ }
catch(E3&) { /*...*/ }
必须在代码中产生"somehwere",如下所示:
if(e instanceof(E1)) { /*...*/ }
else if(e instanceof(E2)) { /*...*/ }
else if(e instanceof(E3)) { /*...*/ }
有一些适当的instanceof
定义(从Java中窃取的术语...这样的定义现在需要比较E<x>
的RTTI是否与e
的RTTI匹配,或者e
的任何基类之一;当然,对于这样的比较,E<x>
的RTTI必须在编译时可用,因此E<x>
的完整定义。
旁注:如果现在 RTTI 在某种泛型列表中包含基类的 RTTI,那么在编译时甚至不再需要知道抛出的异常的确切类型。
- 您应该在什么时候创建自己的异常类型
- 为什么标准不允许通过引用捕获不完整的异常类型?
- 如何修复"ctypes"。参数错误:参数 2:<键入"异常.类型错误">:RaspberryPi 中的错误类型"错误
- 提出异常并处理C 的某些异常类型的正确方法是什么?
- 无法在谷歌测试中检查异常类型
- QT创建者和MSVC-忽略调试时特定的异常类型
- 如何捕获除使用 GDB 的异常类型之外的所有异常类型
- 异常是否应具有标志/消息,或者每个错误应具有异常类型
- 如何在不同的上下文(例如线程)中保留原始异常类型信息
- std::rethrow_exception和抛出的异常类型
- 捕获派生异常类型在 Clang/MacOS X 上失败
- C++:检查是否在没有外部库的情况下抛出了某个异常类型
- 如何猜测 libpqxx C++库函数引发的异常类型
- 获取异常类型
- catch语句如何在没有反射的情况下识别异常类型
- 我们应该使用标准库中的异常类型吗?
- 为什么我的程序从异常中崩溃,即使我捕获了异常类型
- 如何在Mac上从c++程序中自动获取异常类型和消息
- close()抛出什么异常类型
- c++中无法捕获异常:无法识别异常类型