我应该在C+;中使用异常说明符吗+;? 在C++中,可以指定函数可以使用异常说明符,也可以不使用异常说明符。例如: 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

我应该在C+;中使用异常说明符吗+;? 在C++中,可以指定函数可以使用异常说明符,也可以不使用异常说明符。例如: 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,c++,function,exception,throw,specifier,C++,Function,Exception,Throw,Specifier,我怀疑是否实际使用它们,因为: 编译器并没有以任何严格的方式强制执行异常说明符,因此好处不大。理想情况下,您希望得到一个编译错误 如果函数违反了异常说明符,我认为标准行为是终止程序 在VS.Net中,它将throw(X)视为throw(…),因此对该标准的遵从性不强 您认为应该使用异常说明符吗? 请回答“是”或“否”,并提供一些理由来证明您的答案。通常我不会使用异常说明符。但是,如果有任何其他异常来自于所讨论的函数,而程序肯定无法纠正,那么它可能是有用的。在所有情况下,确保清楚地记录该功能可能出

我怀疑是否实际使用它们,因为:

  • 编译器并没有以任何严格的方式强制执行异常说明符,因此好处不大。理想情况下,您希望得到一个编译错误
  • 如果函数违反了异常说明符,我认为标准行为是终止程序
  • 在VS.Net中,它将throw(X)视为throw(…),因此对该标准的遵从性不强
  • 您认为应该使用异常说明符吗?

    请回答“是”或“否”,并提供一些理由来证明您的答案。

    通常我不会使用异常说明符。但是,如果有任何其他异常来自于所讨论的函数,而程序肯定无法纠正,那么它可能是有用的。在所有情况下,确保清楚地记录该功能可能出现的异常

    是的,从具有异常说明符的函数中抛出非指定异常的预期行为是调用terminate()


    <>我也会注意到Scott Meyers用更有效的C++来解决这个问题。他的有效C++和更有效C++是高度推荐的书籍。

    如果你编写的代码将被人们用来查看函数声明,而不是周围的任何评论,那么规范会告诉他们他们可能想捕捉哪些异常。
    否则,我发现除了使用
    throw()
    以外的任何东西都没有特别的用处来表示它不会抛出任何异常。

    是的,如果您对内部文档感兴趣的话。或者写一个别人会用到的图书馆,这样他们就可以不用查阅文档就能知道发生了什么。抛出或不抛出都可以被视为API的一部分,几乎与返回值一样


    <>我同意,它们在编译编译器中没有正确的java风格,但是它比没有或随意的注释要好。

    避免C++中的异常规范。你在问题中给出的理由是一个很好的开始


    请参阅Herb Sutter的。

    它们对于单元测试非常有用,因此在编写测试时,您知道函数失败时会抛出什么,但编译器中没有强制执行它们。我认为它们是C++中不需要的额外代码。无论您选择哪一种,您都应该确保在整个项目和团队成员中遵循相同的编码标准,以便代码保持可读性。

    以下是几个例子来说明原因:

  • 模板代码无法编写,但有异常规范

    template<class T>
    void f( T k )
    {
         T x( k );
         x.x();
    }
    
    可能演变成

    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();
    }
    

  • 然而,当您的库只是抛出您自己的异常时,您可以使用异常规范来说明您的意图。

    gcc将在您违反异常规范时发出警告。我所做的是使用宏,仅在“lint”模式下使用异常规范,编译时明确地进行检查,以确保异常符合我的文档。

    我认为标准的例外约定(对于C++)
    异常规范是C++标准中的一个实验,大多数实验都失败了。 例外情况是,no-throw说明符很有用,但是您还应该在内部添加适当的try-catch块,以确保代码与说明符匹配。赫伯·萨特(Herb Sutter)有一页关于这个主题的文章

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

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

    例外保证 不保证: 无法保证方法发生异常后对象的状态
    在这些情况下,不应再使用该对象

    基本保证: 在几乎所有情况下,这应该是方法提供的最低保证。
    这保证了对象的状态定义良好,并且仍然可以一致地使用

    强担保:(又名交易担保) 这保证了该方法将成功完成
    或者将引发异常,并且对象状态不会更改

    无投掷保证: 该方法保证不允许任何异常传播出该方法。
    所有析构函数都应提供此保证。
    |注意:当异常已经传播时,如果异常逃逸析构函数
    |申请将终止


    唯一有用的异常说明符是“throw()”,如“dots not throw”。

    否。如果使用了它们,并且抛出了未指定的异常(由代码或由代码调用的代码引发),则默认行为是立即终止程序


    <> P.>我相信,在当前C++ C++标准中,它们的用法已被禁止。但是,如果与std::unexpected结合使用,它们有很好的用途

    我在一些项目中使用异常规范编写代码,然后使用一个函数调用set_unexpected(),该函数将抛出我自己设计的特殊异常。此异常在构造时会获取回溯(以特定于平台的方式),并从std::bad_异常派生(如果需要,允许传播它)。如果它导致
    int lib_f();
    
    void g() throw( k_too_small_exception )
    { 
       int k = lib_f();
       if( k < 0 ) throw k_too_small_exception();
    }
    
    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;
    }