当异常变量未定义时,通过引用捕获



在捕获异常时,标准指南是按值抛出,按引用捕获。在我看来,这有两个原因:

  1. 如果异常是由于内存不足异常而抛出的,我们不会调用可能终止程序的复制构造函数。
  2. 如果异常是继承层次结构的一部分,我们可能会对异常进行对象切片。

如果我们没有在catch块中定义异常名称的场景是这些关注点(实际上是1。如果我们没有变量的名称,切片将不会是一个问题)仍然有效吗?

例如:

catch(my_exception)
{ ... }

catch(my_exception &)
{ ... }

在这种情况下,如果异常被值捕获,程序是否仍然有可能终止?我的感觉是技术上仍然是可能的。

注意:我问这个问题是因为我不得不审查在这种情况下使用按值捕获的人的代码。正如问题所示,我不完全确定这两种选择的技术影响,但我认为在这种情况下,无论如何,通过引用捕获的一致性更好(在任何情况下,通过引用捕获都没有缺点)。

对于未命名的异常对象,该标准不需要特别的优化。相反,它需要一种效果,就好像临时对象被复制初始化了。这种复制会导致内存被动态分配。

N3290§15.3/16 :
如果异常声明指定了一个名称,那么它声明了一个变量,该变量是复制初始化(8.5)异常对象。如果异常声明表示对象类型,但未指定名称,则从异常对象复制初始化临时对象(12.2)(8.5)。变量或临时变量的生存期当处理程序退出时结束,在处理程序中初始化的所有自动对象销毁之后。

上面的段落没有提到通过引用捕获,因此人们可以合理地得出结论,无论异常对象是否通过引用捕获,它都适用;无论如何都要构造一个副本。

然而,这与下一段相矛盾:

N3290§15.3/17 :
当处理程序声明非常量对象时,对该对象的任何更改都不会影响临时对象通过执行抛出表达式初始化的对象。的引用时对于非常量对象,对引用对象的任何更改都是对初始化的临时对象的更改当抛出表达式被执行时,如果该对象被重新抛出,该表达式将生效。

因此,声明类型T& (Tconst)是c++ 11要求直接引用抛出对象而不是复制的唯一情况。在c++ 03中也是如此,除了c++ 03有一些关于as-if优化的额外措辞。因此,对于正式格式,首选项应该是

    catch( T& name )

    catch( T& )

然而,我总是捕捉到像catch( T const& )这样的异常。从实际的角度来看,人们可能会假设编译器会将其优化为对抛出对象的直接引用,尽管可能会设计出观察到的程序效果是非标准的情况。例如<evil grin>

#include <stdio.h>
#include <stdexcept>
struct Error
    : std::runtime_error
{
public:
    static Error* pThrown;
    char const* pMessage_;
    Error()
        : std::runtime_error( "Base class message" )
        , pMessage_( "Original message." )
    {
        printf( "Default-construction of Error object.n" );
        pThrown = this;
    }
    Error( Error const& other )
        : std::runtime_error( other )
        , pMessage_( other.pMessage_ )
    {
        printf( "Copy-construction of Error obejct.n" );
    }
    char const* what() const throw() { return pMessage_; }
};
Error*  Error::pThrown  = 0;
int main()
{
    printf( "Testing non-const ref:n" );
    try
    {
        throw Error();
    }
    catch( Error& x )
    {
        Error::pThrown->pMessage_ = "Modified message.";
        printf( "%sn", x.what() );
    }
    printf( "n" );
    printf( "Testing const ref:n" );
    try
    {
        throw Error();
    }
    catch( Error const& x )
    {
        Error::pThrown->pMessage_ = "Modified message";
        printf( "%sn", x.what() );
    }
}

对于mingwc++ 4.4.1和Visual c++ 10.0,输出都是& help;

<>之前测试非const ref:错误对象的默认构造。修改后的信息。测试常量ref:错误对象的默认构造。修改后的信息之前一个迂腐的形式主义者可能会说两个编译器都不一致,没有为Error const&的情况创建一个副本。一个纯粹的实践者可能会说,嘿,你还期望什么?而我,我说标准中的措辞在这里远非完美,如果有的话,人们应该期望澄清明确地允许上面的输出,这样通过引用const进行捕获既安全又最有效。

对wrt求和。OP的问题:

  • 通过引用捕获不要调用可能终止程序的复制构造函数

  • 标准只保证引用非const

  • 在实践中,如图所示,即使程序结果受到影响,也保证引用const

干杯,hth。,

我更喜欢通过引用来捕获。编译器可以将异常作为优化丢弃而不进行复制,但这只是一种可能性

可能有不可见的数据与你的异常相关联,例如一个虚函数表。

虚表是一种不可见的数据结构,它携带着关于在哪里可以找到特定的多态(即virtual)成员函数的信息。一般情况下,这个表会占用对象本身的一些内存。这可能是一个指针的大小到一些外部表,甚至是完整的表。一如既往,这要看情况。

最新更新