当捕获异常时,标准指导是按值抛出,通过引用捕获。据我了解,这有两个原因:
如果我们有一个我们没有在catch块中定义异常名称的场景是这些问题(实际上是1.,因为如果我们没有变量的名称,切片将不会成为问题)有效?
例如:
catch(my_exception)
{ ... }
或
catch(my_exception &)
{ ... }
如果在这种情况下由值捕获的异常,程序是否仍有可能终止?我的感觉是技术上仍然可行。
注意:我问这个是因为我必须审查某人的代码,他们在这种情况下按值列出了值。正如问题所示,我不完全确定任何一种选择的技术影响,但我认为就稳定性而言,最好在这种情况下通过引用而不管(在任何情况下都没有引用的依据)
答案 0 :(得分:5)
在未命名的异常对象的情况下,标准不需要特殊优化。相反,它需要一个效果,好像临时是复制初始化。这种复制可能导致内存被动态分配。
N3290§15.3/ 16 :
如果 exception-declaration 指定了一个名称,它会声明一个从中复制初始化(8.5)的变量。 异常对象。如果 exception-declaration 表示对象类型但未指定名称,则从异常对象复制初始化(8.5)临时(12.2)。变量或临时的生命周期 在处理程序中初始化的任何自动对象的销毁之后,处理程序退出时结束。
上面的段落没有提到引用,因此可以合理地得出结论,无论异常对象是否被引用捕获,它都适用;无论如何都要构建一个副本。
然而,这与下一段相矛盾:
N3290§15.3/ 17 :
当处理程序声明一个非常量对象时,对该对象的任何更改都不会影响临时对象 通过执行 throw-expression 初始化的对象。当处理程序声明对引用的引用时 非常量对象,对引用对象的任何更改都是对已初始化的临时对象的更改 当 throw-expression 被执行时,如果该对象被重新抛出则会生效。
因此,声明类型T&
(T
非 - const
)是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( "%s\n", x.what() );
}
printf( "\n" );
printf( "Testing const ref:\n" );
try
{
throw Error();
}
catch( Error const& x )
{
Error::pThrown->pMessage_ = "Modified message";
printf( "%s\n", x.what() );
}
}
使用MinGW g ++ 4.4.1和Visual C ++ 10.0,输出为......
Testing non-const ref: Default-construction of Error object. Modified message. Testing const ref: Default-construction of Error object. Modified message
一个迂腐的形式主义者可能会说两个编译器都不符合要求,没有为Error const&
案例创建副本。一个纯粹实际的从业者可能会说嘿,你还有什么期望?而我,我说标准中的措辞在这里非常完美,如果有的话,人们应该期望澄清明确允许上面的输出,所以通过引用const
也是安全的并且最有效率。
总结一下。 OP的问题:
通过引用捕获不会调用可能会终止程序的复制构造函数。
标准仅保证此参考非const
。
在实践中,如图所示,即使计划结果受到影响,也可以保证参考const
。
干杯&amp;第h。,
答案 1 :(得分:1)
我更愿意通过引用来捕捉。编译器可以将异常作为优化丢弃并且不进行复制,但这只是可能性。通过引用捕获可以确定。
答案 2 :(得分:1)
可能存在与您的例外相关联的不可见数据,例如一个vtable。
vtable是一个不可见的数据结构,它携带有关可以找到某些多态(即virtual
)成员函数的位置的信息。在一般情况下,该表花费了对象本身中的一些内存。这可能是通过指针的大小进入一些外部表,甚至是完整的表。一如既往,这取决于。