如何向编译器表明函数总是抛出? [复制]
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。这是你期望发生的事情吗?以上是关于如何向编译器表明函数总是抛出? [复制]的主要内容,如果未能解决你的问题,请参考以下文章