异常处理和强制

Posted

技术标签:

【中文标题】异常处理和强制【英文标题】:Exception handling and coercion 【发布时间】:2013-02-12 10:46:07 【问题描述】:
try

    throw Derived();

catch (Base&)

    std::cout << "subtyping\n";


try

    throw "lol";

catch (std::string)

    std::cout << "coercion\n";

输出:

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

为什么异常处理对子类型很好,但对强制却不行?

【问题讨论】:

当您抛出异常以尝试匹配异常处理程序时,不会创建新对象。 因为Derived() Base 并且可以被Base&amp; 绑定,但"coercion" 不是std::string。 catch 子句捕获 existing 对象。 如果有第二个 catch 块采用 myOwnString 类型会发生什么?那岂不是模棱两可? @Pubby 好吧,如果有第二个 catch 块占用不同的 Base 怎么办? 这个问题仍然没有被接受的答案有什么特别的原因吗? 【参考方案1】:

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

三个主要区别是:

异常总是至少被复制一次(根本无法避免) catch 子句按照声明的顺序进行检查(不是最合适的) 它们受到较少形式的类型转换: 基于继承的覆盖, 从有类型指针转换为无类型指针(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&amp;无论放在哪里都无法访问(假设我们抛出Leaf

通常很简单:顺序很重要。

【讨论】:

【参考方案2】:

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

处理程序匹配E if 类型的异常对象

——处理程序的类型为cv Tcv T&amp;ET 是同一类型(忽略***cv-qualifiers), 或

——处理程序的类型为cv Tcv T&amp;TE 的明确公共基类,或者

——处理程序的类型是cv1 T* cv2E是一个指针类型,可以转换为 由一个或两个处理程序

标准指针转换 (4.10) 不涉及到指向私有或受保护的指针的转换 或模棱两可的类

资格转换

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

[...]

【讨论】:

以上是关于异常处理和强制的主要内容,如果未能解决你的问题,请参考以下文章

如何强制 WCF 线程中未处理的异常使进程崩溃?

第十章.异常处理

Java 异常处理

java中的异常和处理

Delphi中的异常处理(10种异常来源处理精确处理)

运行时异常和一般异常(受检异常)区别是什么?