为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C++
慕婉清6462132 2019-10-25 10:46:55
在C ++中,您可以使用异常说明符来指定一个函数可能会抛出异常,也可能不会抛出异常。例如:void foo() throw(); // guaranteed not to throw an exceptionvoid bar() throw(int); // may throw an exception of type intvoid baz() throw(...); // may throw an exception of some unspecified type由于以下原因,我对实际使用它们表示怀疑:编译器实际上并没有以任何严格的方式强制执行异常说明符,因此好处并不大。理想情况下,您希望获得一个编译错误。如果函数违反异常说明符,我认为标准行为是终止程序。在VS.Net中,它将throw(X)视为throw(...),因此对标准的遵循性不强。您认为应该使用异常说明符吗?请回答“是”或“否”,并提供一些理由来证明您的回答合理。
查看完整描述

3 回答

?
慕的地8271018

TA贡献1796条经验 获得超4个赞

没有。


这里有几个例子说明为什么:


模板代码无法使用异常规范编写,


template<class T>

void f( T k )

{

     T x( k );

     x.x();

}

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


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


virtual void open() throw( FileNotFound );

可能演变成


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

你真的可以写成


throw( ... )

第一个是不可扩展的,第二个是过于雄心勃勃的,第三个实际上是您在编写虚拟函数时的意思。


旧版代码


当您编写依赖于另一个库的代码时,您真的不知道当发生严重错误时它可能会做什么。


int lib_f();


void g() throw( k_too_small_exception )

   int k = lib_f();

   if( k < 0 ) throw k_too_small_exception();

}

glib_f()抛出时将终止。(在大多数情况下)这不是您真正想要的。std::terminate()永远不应该被调用。总是让应用程序因未处理的异常而崩溃(从中可以检索堆栈跟踪)总是比静默/剧烈地消亡更好。


编写返回常见错误并在特殊情况下抛出的代码。


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;

}

但是,当您的库仅引发您自己的异常时,您可以使用异常规范说明您的意图。


查看完整回答
反对 回复 2019-10-25
?
烙印99

TA贡献1829条经验 获得超13个赞

我认为除约定外(对于C ++),标准

例外说明符是在C ++标准中进行的一项实验,多数失败。

唯一的例外是,不抛出说明符很有用,但您还应该在内部添加适当的try catch块,以确保代码与说明符匹配。Herb Sutter在此页面上有一个页面。戈特82


另外,我认为值得描述例外保证。


这些基本上是有关对象的状态如何受到异常转义的方法的文档。不幸的是,它们没有被编译器强制执行或以其他方式提及。

提升和例外


例外保证

不保证:

在异常转义方法之后,无法保证对象的状态。

在这些情况下,不应再使用该对象。


基本保证:

在几乎所有情况下,这都应该是方法提供的最低保证。

这保证了对象的状态定义正确,并且仍然可以被一致地使用。


强有力的保证:(又名交易保证)

这保证了该方法将成功完成,

否则将引发异常并且对象状态不会更改。


无投掷保证:

该方法保证不允许异常传播到该方法之外。

所有破坏者都应作出此保证。

| 注意:如果在已传播异常的情况下异常逃逸了析构函数

| 该应用程序将终止


查看完整回答
反对 回复 2019-10-25
?
波斯汪

TA贡献1811条经验 获得超4个赞

异常规范不是C ++中非常有用的工具。但是,如果与std :: unexpected结合使用,则/ is /有很好的用途。

在某些项目中,我要做的是编写具有异常规范的代码,然后使用将抛出我自己设计的特殊异常的函数调用set_unexpected()。构造后,此异常获取回溯(以特定于平台的方式),并从std :: bad_exception派生(如果需要,可以传播该异常)。如果它像往常一样引起了一个terate()调用,则回溯将由what()打印(以及引起它的原始异常;不难发现),因此我获得了合同所在位置的信息。违反,例如引发了意外的库异常。

如果这样做,我将永远不允许传播库异常(std异常除外),并从std :: exception派生我的所有异常。如果库决定抛出,我将捕获并转换为自己的层次结构,从而使我能够始终控制代码。由于明显的原因,调用依赖函数的模板化函数应避免使用异常规范。但是无论如何,很少有带有库代码的模板化函数接口(很少有库确实以有用的方式使用模板)。


查看完整回答
反对 回复 2019-10-25
  • 3 回答
  • 0 关注
  • 403 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信