我的头文件中有一些现有代码,需要在 C++03 和 C++11 的上下文中使用
它定义了一个宏
TABORT
,它接受 printf
样式的格式字符串和要使用该字符串格式化的参数,将结果打印到 stdout
,然后调用 std::abort
本质上,类似于
#define TABORT(...) do { fprintf(stderr, "Aborting at %s:%d for reason: ", __FILE__, __LINE__); fprintf(stderr, __VA_ARGS__); std::abort(); } while(0)
我想添加一些逻辑来捕获计算
__VA_ARGS__
会引发异常的情况,从而阻止对 std::abort
的调用。例如,在以下内容中:
if (SomethingReallyBadHappened())
TABORT("Aborting because %s", GetReallyBadDetails().c_str());
如果
GetReallyBadDetails
抛出异常,我想确保调用中止(此处,而不是在某些异常展开之后)。
所以,我做了类似的事情:
#define TABORT(...) do { fprintf(stderr, "Aborting at %s:%d for reason: ", __FILE__, __LINE__); try { fprintf(stderr, __VA_ARGS__); } catch (...) { fprintf(stderr, "<Failed to evaluate abort message>\n"); } std::abort(); } while(0)
但是,当在标记为 __forceinline
的函数中使用宏时,这会导致 Visual Studio 中出现
C4714 警告,可能是由于
在某些情况下,编译器不会内联特定函数 机械原因。例如,编译器不会内联:
- 带有 try(C++ 异常处理)语句的函数。
因此,为了避免该警告(并保持先前确定需要内联的内联函数inlined[我希望这与分析一起完成......]),我正在考虑做类似的事情
// In header
// Assume this is like std::function except construction from a lambda can't throw
template <typename Sig>
class function_ref;
using PrintAbortMsg = function_ref<void(const char*)>;
void [[noreturn]] do_tabort(const char* file, int line, function_ref<void(PrintAbortMsg &)> msgGenerator) noexcept;
#define TABORT(...) do_tabort(__FILE__, __LINE__, [&](PrintAbortMsg& print) { print(SprintfToStdString(__VA_ARGS__).c_str()); })
// In cpp
void do_tabort(const char* file, int line, function_ref<void(PrintAbortMsg&)> msgGenerator) noexcept
{
fprintf(stderr, "Aborting at %s:%d for reason: ", __FILE__, __LINE__);
try
{
msgGenerator([](const char* msg) { fprintf(stderr, "%s\n", msg); });
}
catch (...)
{
fprintf(stderr, "<Failed to evaluate abort message>\n");
}
std::abort();
}
我认为可以在 C++11 的上下文中工作,但我不确定如何做一些适用于 C++03 的事情。我不想触及该宏的现有用法。
struct abort_no_matter_what {
~abort_no_matter_what()
{
std::abort();
}
};
现在,一旦 abort_no_matter_what
构建完毕,你的鹅就熟了:
{
abort_no_matter_what i_said;
// Some code
}
有问题的某些代码最终总是会调用std::abort
。当执行正常离开作用域时;或者当抛出异常时,因为堆栈展开将调用析构函数,该析构函数将调用
std::abort
并掩盖事物。所以,现在,你的宏就变成了:
#define TABORT(...) do { abort_no_matter_what i_said; \
fprintf(stderr, "Aborting at %s:%d for reason: ", __FILE__, __LINE__); \
fprintf(stderr, __VA_ARGS__); } while(0)