为啥我应该在抛出异常指针时使用按引用捕获

Posted

技术标签:

【中文标题】为啥我应该在抛出异常指针时使用按引用捕获【英文标题】:Why should i use catch by reference when exception pointers are thrown为什么我应该在抛出异常指针时使用按引用捕获 【发布时间】:2013-02-01 20:49:15 【问题描述】:

当通过引用捕获异常时,我获得的唯一优势是避免生成异常对象的副本?基本上是区别

try

    CString a_csSQL = _T("SELECT * FROM Library");
    CDatabase aDB;
    aDB.OpenEx(g_csConnectionStringWdDSN,CDatabase::noOdbcDialog));
    aDB.ExecuteSQL(a_csSQL);

catch(CDBException *& ex)

    ex->Delete();

try

    CString a_csSQL = _T("SELECT * FROM Library");
    CDatabase aDB;
    aDB.OpenEx(g_csConnectionStringWdDSN,CDatabase::noOdbcDialog))
    aDB.ExecuteSQL(a_csSQL);

catch(CDBException * ex)

    ex->Delete();

【问题讨论】:

异常应该按值抛出并通过引用捕获,而不是通过指针抛出。通过引用捕获指针是没有意义的(双关语)。此外,除了不制作副本(从而避免切片)之外,您还要确保异常的复制构造函数不会抛出异常,我同意,如果发生这种情况会很愚蠢,但最好确保您的成功。跨度> 引用也可以确保这一点。 MFC 通过指针抛出异常。使用 MFC 的人别无选择。 @sansix 我在此纠正你:你错了。 @sansix * & 只是不要在这里互相取消。你可能在想int a = 5; int b = *(&a);。在这种情况下,ab 都将是 5,但这与一般说“* & 相互抵消”完全不同。特别是,在我的示例中,& 获取地址,而在问题中讨论的情况下,& 表示引用。 【参考方案1】:

您发布的两个代码之间的区别在于,第一个代码通过引用捕获指向异常的 指针,第二个代码通过引用捕获指向异常的 指针价值。在这两种情况下都不会复制异常,因为您正在处理指针。

一般来说,异常应该按值抛出,按引用捕获。 C++ 标准库的设计考虑了这种期望。但是,较旧的库(例如 MFC)像您在此处所做的那样由 pointer 引发异常,并且预计会被指针捕获。

通过值和通过引用捕获指针之间没有有效的区别,除了如果你通过引用捕获给你删除异常的(完全无用的)选项,分配一个新的异常相同的指针,并重新抛出相同的异常指针。

【讨论】:

在MFC中,删除异常的选项不是没用,而是必要的。 MFC 异常使用new 动态分配,处理它们的catch 块预计会调用Delete() 成员函数来销毁对象。 @Praetorian:我想你误解了我的意思。当然你应该Delete() 它,但是通过引用捕获一个指针也允许你为同一个指针分配其他东西,使用throw; 抛出同一个指针,但指向不同的异常。 (当然,这完全没用) 抱歉,我确实误会了。是的,那样做确实没用。【参考方案2】:

如果异常是由指针引发的,则可以避免使用引用。

如果按值抛出异常,则确实需要引用。

【讨论】:

以上是关于为啥我应该在抛出异常指针时使用按引用捕获的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中通过指针捕获异常

为啥内核驱动程序在抛出异常时无法更新注册表值?

为啥方法在抛出异常后不需要返回值?

为啥java中Exception的对象能够获取子类的信息.

了解Java在抛出异常时的堆栈展开

抛出异常时中断