在所有三个主要实现上通过引用捕获转换后的临时值

Quu*_*one 7 c++ exception language-lawyer

我对所有三个主流编译器/运行时对此 C++ 代码( Godbolt)的处理感到困惑:

\n
int main() {\n    int i = 42;\n    try {\n        throw &i;\n    } catch (void*&) {\n        puts("incorrectly hit?");\n    } catch (...) {}\n    try {\n        throw nullptr;\n    } catch (void*&) {\n        puts("incorrectly hit?");\n    } catch (...) {}\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,此处抛出的“异常对象”是 resp 类型的对象int*std::nullptr_t。但被捕获的对象是类型void*。唯一可行的方法是运行时创建一个void*从异常对象类型转换而来的临时对象,对吧?那么void*&catch 处理程序中的 必须引用临时对象,而不是实际的运行中异常对象?

\n

仔细看看措辞,[ except.handle ]说:

\n
\n

处理程序与类型为Eif的异常对象匹配

\n
    \n
  • 处理程序的类型为cv Tor ,cv T&并且ET是相同类型(忽略顶级 cv 限定符),或者
  • \n
  • 处理程序的类型为cv Torcv T&且是, orT的明确公共基类E
  • \n
  • 处理程序的类型为cv Torconst T&其中T是指针或指向成员的指针类型,并且是可以通过 [...] 标准指针转换 [...]E转换为的指针或指向成员的指针类型,或者T
  • \n
  • 处理程序的类型为cv Tconst T&其中T是指针或指向成员的指针类型,并且Estd\xe2\x80\x8b::\xe2\x80\x8bnullptr_t
  • \n
\n
\n

这些要点似乎都不适用。那么,这三个供应商允许这个处理程序受到攻击的行为难道就是错误的吗?catch[except.handle] 措辞并不是新的;它最近在 2016 年被触及(CWG2093 ),但似乎是在 2012 年左右作为CWG388CWG729的结果而引入的。

\n

388 号决议称“该决议需要更改 ABI”;这是否意味着所有三个供应商根本就懒得去实施它?

\n

(更新为添加:[except.handle]/15说:“当处理程序声明对对象的引用时,对引用对象的任何更改都是对异常对象的更改,并且如果该对象被重新抛出,则会生效”\xe2\ x80\x94 但当引用绑定到转换后的临时变量时,这显然是不正确的。我认为可以通过在“引用”之前添加形容词“非常量”来挽救该句子。)

\n