如何向编译器表明函数总是抛出? [复制]

Posted

技术标签:

【中文标题】如何向编译器表明函数总是抛出? [复制]【英文标题】:How to signify to the compiler that a function always throws? [duplicate] 【发布时间】:2009-06-28 07:59:23 【问题描述】:

当调用总是从返回值的函数中抛出的函数时,编译器通常会警告并非所有控制路径都返回值。合情合理。

void AlwaysThrows()  throw "something"; 

bool foo()

    if (cond)
        AlwaysThrows();
    else
        return true; // Warning C4715 here

有没有办法告诉编译器 AlwaysThrows 按照它说的做?

我知道我可以在函数调用之后添加另一个throw

 AlwaysThrows(); throw "dummy"; 

而且我知道我可以明确禁用警告。但我想知道是否有更优雅的解决方案。

【问题讨论】:

【参考方案1】:

使用noreturn 属性。这在最新版本的 C++ 标准第三版 ISO/IEC 14882:2011 的 “7.6.3 Noreturn 属性 [dcl.attr.noreturn]”部分中指定。

标准示例:

[[ noreturn ]] void f()

    throw "error";

【讨论】:

【参考方案2】:

您可以在调用 AlwaysThrows() 之后添加一个虚拟的 return 语句,并附上解释它为什么存在的注释。当您调用的函数总是 exit()s 或 abort()s 时,这也很有用。

【讨论】:

这就是我们在我们的商店所做的。这是避免编译器投诉的最简单方法。您必须确定,尽管该函数总是抛出异常。 如果您这样做,GCC 会抱怨无法访问的代码,因此这不是针对此警告的可移植修复。 @Pait 我们使用一个扩展为类似assert(false); return ; 的宏,它(至少对于不返回引用的函数)几乎完全符合我们的要求(在没有优化的情况下编译时断言,并且不会产生警告)。 @KyleStrand 问题是关于抛出异常的函数而不是断言。您能否详细说明您的宏与问题的关系?此外,像这样的宏仅适用于默认可构造的返回类型。 @Pait 关键是宏解决了您关于 GCC 的“无法访问代码”投诉的观点,默认情况下构造一个适当类型的对象。是的,它仅限于类型是默认可构造的情况。【参考方案3】:

当然,一个问题是你为什么要写这样的代码?显而易见的答案是 AlwaysTrows() 实际上是某种错误报告函数。在我自己的代码中,我实际上使用宏来进行错误报告,因为它让我可以执行字符串格式化并获取标准的__LINE____FILE__ 宏。宏大致如下:

#define ATHROW( msg )                                               \
                                                                   \
    std::ostringstream os_;                                         \
    os_ << msg;                                                     \
    throw ALib::Exception( os_.str(), __LINE__, __FILE__ );         \

异常构造函数在哪里进行任何额外的格式化、额外的日志记录等。这样做的副作用当然是编译器可以看到正在抛出异常,所以当我说这样的话时:

int f() int val ) 
   if ( val >= BADVALUE ) 
       ATHROW( "Invalid value " << val << " for val" );
   
   else 
       return val / 3;
   

那么我不会收到关于 f() 没有返回值的警告。

【讨论】:

我通常反对使用宏,但是它们对于抛出异常非常方便!! C++20 有std::source_location,所以不再需要 MACRO 来处理行和文件。【参考方案4】:

使用 Visual C++,您可以使用__declspec(noreturn)

【讨论】:

有便携的解决方案吗? Porable:不,语言规范中没有这样的东西。 GCC 理解 __attribute__((noreturn)),如果这有帮助的话...... 如下所述[[noreturn]]自C++11【参考方案5】:

我也遇到过这个烦人的小问题。通常场景涉及:

    我想重构几个 catch 块中的一些常见代码行 上述所有 catch 块最终都会重新引发异常。

虽然您可以在总是抛出的方法之后放置一个虚拟返回,但这可能会冒犯您的程序员的强迫症。

我使用的折衷方案是不让被调用的方法抛出它的异常,而是返回它。然后,当您调用该方法时,只需抛出返回值:

Exception HandleException() 
 
    // Do stuff, like some logging maybe
    return SomeException("something"); 


bool foo()
    
   if (cond)        
       throw HandleException();    
   else        
       return true; // no more warning

这样,您不必添加任何额外的代码行。

【讨论】:

正如所写,这似乎将 SomeException 分割成 Exception。这是你期望发生的事情吗?

以上是关于如何向编译器表明函数总是抛出? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

当任何数学运算产生“NaN”时,如何强制 C# 编译器抛出异常?

声明一个总是抛出异常的方法?

GWT 2.5.1编译始终抛出Java堆空间错误

throw与throws的区别

编译器何时不生成移动构造函数和移动赋值?

这个 if 语句会抛出异常还是忽略它? [复制]