异常处理和强制

fre*_*low 12 c++ exception-handling language-design coercion subtyping

try
{
    throw Derived();
}
catch (Base&)
{
    std::cout << "subtyping\n";
}

try
{
    throw "lol";
}
catch (std::string)
{
    std::cout << "coercion\n";
}
Run Code Online (Sandbox Code Playgroud)

输出:

subtyping
terminate called after throwing an instance of 'char const*'
Run Code Online (Sandbox Code Playgroud)

为什么异常处理对子类型有好处,但不是强制?

eme*_*esx 18

捕获抛出异常与将参数传递给函数完全不同.有相似之处,但也有微妙的差异.

3个主要区别是:

  • 异常总是至少复制一次(根本无法避免)
  • catch 条款按照声明的顺序进行检查(不是最合适的)
  • 它们受较少形式的类型转换的影响:
    • 基于继承的覆盖,
    • 从类型转换为无类型指针(const void*捕获任何指针)

任何其他类型的转换是不允许的(如intdouble,或隐const char*string-您的例子).

关于您在评论中的问题 假设存在层次结构:

class Base {}; 
class Derived: public Base {};
class Base2 {};
class Leaf: public Derived, public Base2 {};
Run Code Online (Sandbox Code Playgroud)

现在,根据catch子句的顺序,将执行适当的块.

try {
    cout << "Trying ..." << endl;
    throw Leaf();

} catch (Base& b) {
    cout << "In Base&";

} catch (Base2& m) {
    cout << "In Base2&"; //unreachable due to Base&

} catch (Derived& d) {
    cout << "In Derived&";  // unreachable due to Base& and Base2&
}
Run Code Online (Sandbox Code Playgroud)

如果切换BaseBase2捕获订单,您会发现不同的行为.如果Leaf私下继承Base2,那么catch Base2&无论放在哪里都会无法到达(假设我们抛出一个Leaf)

一般来说很简单:订单很重要.


And*_*owl 8

C++ 11标准的第15.3/3段定义了处理程序与某个异常对象匹配的确切条件,并且这些条件不允许用户定义的转换:

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

-该处理程序的类型是cv Tcv T&ET是相同的类型(忽略顶层cv-qualifiers),或

- 处理程序是类型cv Tcv T&,T是一个明确的公共基类E,或

- 处理程序是类型的cv1 T* cv2,E是一种指针类型,可以通过其中一个或两个转换为处理程序的类型

  • 标准指针转换(4.10),不涉及到指向私有或受保护或模糊类的指针的转换

  • 资格转换

-该处理程序是一个指针或指针构件类型和Estd::nullptr_t.

[...]