旧代码在析构函数中引发异常
Legacy code throws exception in destructor
我正在维护相当旧的遗留代码。我的先驱是异常处理的先驱(<2000)。处理非标准行为的投掷和接球逻辑似乎已经奏效。
他们实现了一个很好的投掷方式:
TL_THROW_EXCEPTION(ISQL_MSG_XML_PARSER_ERROR) << msg;
TL_THROW_EXCEPTION扩展为:
TLThrowTec::CTLThrowExceptionTechnical::ThrowT(__FILE__,__LINE__,
ISQL_MSG_XML_PARSER_ERROR) << msg;
它在堆栈上创建一个 TLThrowTec::CTLThrowExceptionTechnical 实例,并使用 shift 操作来设置消息字符串。析构函数创建并引发异常。
2008 年 stackoverflow 中的条目解释了当年的状态: 从析构函数中抛出异常,当时似乎已经起作用了。
但是现在Visual Studio 17允许投掷,但不能再接住。
由于遗留代码是整个系统的一部分,因此它会生成日志文件条目,例如"未处理的操作系统异常"。
我想在不对源代码进行太多更改的情况下恢复捕获逻辑。最好是带 #define TL_THROW_EXCEPTION。
有没有办法重新定义宏,以便随消息一起引发异常?
如果我搜索TL_THROW_EXCEPTION这是最后一行:
匹配行数:770 匹配文件:217 搜索文件总数:3159
我不喜欢碰他们所有人。
Modern C++ 默认情况下将所有析构函数指定为非抛出。如果从任何指定为非抛出的函数引发异常,则程序将立即终止。这是因为抛出析构函数是不受欢迎的。析构函数在堆栈展开期间自动调用,而异常已在传输中。在这种情况下,再次投掷本身会终止程序。所有标准容器都会在所包含对象的析构函数抛出时警告 UB。
但是您的用例不容易触发任何这些。ThrowT
对象在我看来是作为临时对象创建的,可以立即抛出一些东西,但它们不会在堆栈展开其他东西时徘徊以调用它们的析构函数。因此,我们可以将它们标记为再次抛出以恢复功能。像这样的东西...
ThrowT::~ThrowT() noexcept(false) {
// as before
}
。将使宏再次工作。
只需将异常创建类型调整为异常,并使用:
#undef TL_THROW_EXCEPTION
#define TL_THROW_EXCEPTION(msg_)
throw YourExceptionType(__FILE__, __LINE__, (msg_))
由于throw
的优先级低于<<
,这将首先计算聚合表达式,然后抛出其结果。
只需修复该类:
- 将
std::uncaught_exceptions()
的结果(复数,而不是单数)保存在 ctor 中。 - 标记 dtor
noexcept(false)
以启用传播异常。 - 仅在调用
std::uncaught_exceptions()
返回保存的计数时才投入 dtor。否则,尝试构建异常会导致异常,并且将自己的异常投入混乱将std::terminate
调用。
我希望您的构造函数使用std::stringstream
.否则,也请考虑解决该疏忽。
有没有办法重新定义宏?
是的,只需取消定义它,然后重新定义,如下所示:
#undef TL_THROW_EXCEPTION
#define TL_THROW_EXCEPTION ...
当然,如果你能想到一种方法来使其成为class
或函数,那么你最好在#undef
它之后再做,而不是使用宏。
所以更像是:
#undef TL_THROW_EXCEPTION
class TL_THROW_EXCEPTION
{ ... }
然后定义构造函数以创建提供所需行为的实例。
- 在析构函数内部处理异常(但不抛出)
- 在 postOrderDelete 上调用析构函数时引发的异常
- 为什么在析构函数中引发异常时不调用重载删除
- 文件流析构函数是否可以在C++中引发异常?
- 为什么没有捕获我来自析构函数的异常
- 析构函数中的互斥锁C++在 Python 中调用 exit() 时会导致异常
- 旧代码在析构函数中引发异常
- 引发导致调用析构函数的异常会使程序崩溃
- 为什么我的析构函数中的异常没有触发 std::终止?
- 如何释放C++异常类析构函数中的变量
- 析构函数中的 C++ 异常
- 在scoped_ptr发生异常的情况下未调用析构函数
- 在由于异常而展开时处理C++析构函数中的pthread取消点
- c++中的Guard,在main中未处理异常时不调用析构函数
- 如何为析构函数指定nothrow异常说明符
- 堆栈异常处理和析构函数展开.如何使用这些信息
- 析构函数的异常调用
- 在 MSVC 中的析构函数中引发异常的异常
- 从保护类析构函数引发异常会导致 std::终止
- 清理C++异常析构函数中的代码