异常处理和强制转换

Exception handling and coercion

本文关键字:转换 异常处理      更新时间:2023-10-16
try
{
    throw Derived();
}
catch (Base&)
{
    std::cout << "subtypingn";
}
try
{
    throw "lol";
}
catch (std::string)
{
    std::cout << "coercionn";
}
输出:

subtyping
terminate called after throwing an instance of 'char const*'

为什么异常处理可以很好地处理子类型,而不能处理强制转换?

捕捉抛出的异常与向函数传递参数有很大不同。有相似之处,但也有细微的差别。

  • 异常总是至少复制一次(根本不可能避免)
  • catch子句按其声明的顺序进行检查(不是最合适的)
  • 它们的类型转换形式较少:
    • 基于继承coversions,
    • 从类型化指针到非类型化指针的转换(const void*捕获任何指针)

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

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

class Base {}; 
class Derived: public Base {};
class Base2 {};
class Leaf: public Derived, public Base2 {};

现在根据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&
}

如果你切换BaseBase2的捕获顺序,你会注意到不同的行为。如果LeafBase2私有继承,那么catch Base2&无论放在哪里都是不可访问的(假设我们抛出Leaf)

一般来说很简单:顺序很重要

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

处理程序匹配E类型的异常对象,如果

-处理程序的类型为cv Tcv T&,并且ET是相同的类型(忽略顶级cv限定符),或者

-处理程序的类型为cv Tcv T&,并且TE的一个明确的公共基类,或

-处理程序的类型为cv1 T* cv2, E是指针类型,可以转换为对象的类型

中的一个或两个处理程序
  • 一个标准的指针转换(4.10),不涉及到private或protected指针的转换或歧义类

  • 资质转换

——处理程序是一个指针或指向成员类型的指针,Estd::nullptr_t

[…)