【发布时间】:2019-03-24 12:13:52
【问题描述】:
我大量使用 noexcept,不幸的是,如果某些传递依赖最终在极少数情况下抛出(我们不知道),崩溃非常难以调试 - 因为 noexcept 导致 std::terminate 被调用。
有没有办法在编译时检测这些违规行为?在下面的例子中 问题很明显,但默认情况下没有编译器捕获它。我意识到这并非在所有情况下都是可能的,但更简单的情况肯定是可能的
#include <stdexcept>
void baz()
{
throw std::runtime_error("std::terminate awaits");
}
void bar()
{
baz();
}
void foo() noexcept
{
bar();
}
神螺栓链接:https://godbolt.org/z/Ooet58
是否有我不知道的编译器标志?捕捉到这一点的静态分析工具怎么样?
【问题讨论】:
-
为此分析深层函数调用似乎很棘手。关于简单地使用
noexcept(false)函数的警告似乎太烦人了。 -
我学会了忽略
noexcept标签,除非我确定我的例程不能抛出。这通常意味着我只标记不调用任何东西的叶子函数。话虽这么说,运算符重载滑入了一个我没有注意到的难以发现的函数调用……你好 std::terminate。叹息 -
我同意“除非你肯定知道,否则不要标记”,但代码会更改。曾经是叶函数的东西被其他人重构,这会调用另一个抛出的函数。或者,您在 noexcept 函数中调用用户提供的回调(例如,您正在编写一个事件循环),然后抛出
-
调试难度如何?注册您自己的终止处理程序并在那里放置一个断点。或者,如果您正在运行无法直接调试的守护进程,请打印堆栈跟踪,甚至更好:创建可以在本地调试的核心转储。
-
在单个编译单元中,这可能很容易处理,尽管我不知道有什么工具可以做到这一点。但从哲学上讲,从共享/动态库调用函数时应该如何检测到这一点?