我应该在 C++ 中使用异常说明符吗?

2021-12-07 00:00:00 function exception c++ throw specifier

在 C++ 中,您可以使用异常说明符指定函数可能会或可能不会引发异常.例如:

In C++, you can specify that a function may or may not throw an exception by using an exception specifier. For example:

void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type

我对实际使用它们持怀疑态度,原因如下:

I'm doubtful about actually using them because of the following:

  1. 编译器并没有真正以任何严格的方式强制执行异常说明符,因此好处并不大.理想情况下,您希望得到编译错误.
  2. 如果函数违反了异常说明符,我认为标准行为是终止程序.
  3. 在 VS.Net 中,它将 throw(X) 视为 throw(...),因此对标准的遵守不强.

您认为应该使用异常说明符吗?
请回答是"或否",并提供一些理由来证明您的回答是正确的.

Do you think exception specifiers should be used?
Please answer with "yes" or "no" and provide some reasons to justify your answer.

推荐答案

没有

以下是几个原因:

  1. 模板代码不可能写出异常规范,

  1. Template code is impossible to write with exception specifications,

template<class T>
void f( T k )
{
     T x( k );
     x.x();
}

副本可能会抛出,参数传递可能会抛出,x() 可能会抛出一些未知的异常.

The copies might throw, the parameter passing might throw, and x() might throw some unknown exception.

异常规范倾向于禁止可扩展性.

Exception-specifications tend to prohibit extensibility.

virtual void open() throw( FileNotFound );

可能演变成

virtual void open() throw( FileNotFound, SocketNotReady, InterprocessObjectNotImplemented, HardwareUnresponsive );

你真的可以把它写成

throw( ... )

第一个是不可扩展的,第二个是野心勃勃的,第三个是你真正的意思,当你写虚函数时.

The first is not extensible, the second is overambitious and the third is really what you mean, when you write virtual functions.

旧代码

当您编写依赖于另一个库的代码时,您真的不知道当出现可怕的错误时它会做什么.

When you write code which relies on another library, you don't really know what it might do when something goes horribly wrong.

int lib_f();

void g() throw( k_too_small_exception )
{ 
   int k = lib_f();
   if( k < 0 ) throw k_too_small_exception();
}

g 将终止,当 lib_f() 抛出时.这(在大多数情况下)不是您真正想要的.std::terminate() 不应该被调用.让应用程序因未处理的异常而崩溃,您可以从中检索堆栈跟踪,总比静默/暴力死亡要好.

g will terminate, when lib_f() throws. This is (in most cases) not what you really want. std::terminate() should never be called. It is always better to let the application crash with an unhandled exception, from which you can retrieve a stack-trace, than to silently/violently die.

编写返回常见错误并在异常情况下抛出的代码.

Write code that returns common errors and throws on exceptional occasions.

Error e = open( "bla.txt" );
if( e == FileNotFound )
    MessageUser( "File bla.txt not found" );
if( e == AccessDenied )
    MessageUser( "Failed to open bla.txt, because we don't have read rights ..." );
if( e != Success )
    MessageUser( "Failed due to some other error, error code = " + itoa( e ) );

try
{
   std::vector<TObj> k( 1000 );
   // ...
}
catch( const bad_alloc& b )
{ 
   MessageUser( "out of memory, exiting process" );
   throw;
}

尽管如此,当您的库只是抛出您自己的异常时,您可以使用异常规范来说明您的意图.

Nevertheless, when your library just throws your own exceptions, you can use exception specifications to state your intent.

相关文章