C++中,静态对象构造函数中的异常会绕过先前静态对象的析构函数
C++, an exception in the constructor of a static object bypasses destructors of prior static objects
我正在研究如何添加C++异常处理来处理现有实时应用程序中的运行时错误。我从封装硬件系统组件驱动程序的对象的构建失败开始,例如位于Raspberry Pi平台SPI总线上的电源监控微控制器。
根据RAII原则,我必须在它们的构造函数中完全初始化这些对象,如果系统资源不可用,例如SPI驱动程序没有加载,这会导致失败的可能性。由于构造函数没有返回值,所以我必须使用异常来处理此类失败。
这些硬件驱动程序对象是静态的(文件范围(。为什么?因此,它们的构造函数会被自动调用,更重要的是,它们的析构函数会在程序退出时被自动调用。此外,我需要从主程序文件中的任何位置获取对象,因为它们代表全局硬件资源。
我并不真正关心如何处理异常(我可以在抛出之前发出有用的错误信息(,但我确实关心程序是否正确终止。
发生的情况是,如果静态分配对象的构造函数失败并抛出异常,则不会调用在失败对象之前的其他静态对象的析构函数。我已经在一个最小的测试台上进行了测试。类Apple、Pear和Orange除了构造函数和析构函数之外什么都没有,它们向stdout声明自己,只是Orange的构造函数随后抛出了一个异常。在主文件中,我按顺序定义了Apple、Pear和Orange的一个静态实例。构造函数在程序执行时被调用,Orange抛出异常,程序结束时不调用Apple和Pear的析构函数。
我在这里错过了什么?
在对类似问题的回答中,例如556655,人们建议:-不在构造函数中引发异常。嗯?-有一个单独的初始化方法,在构造后称为"手动",用于执行任何可能失败的操作。那么RAII呢?(顺便说一句,这就是我现在的情况,没有例外(。-将静态对象更改为指针,并使用新运算符"手动"调用构造函数。然后,在发生故障时,我必须设法调用正确的析构函数,我希望使用异常可以避免这种情况。-将每个静态对象封装在另一个具有访问器函数的对象中,以获得对它的引用。显然,只有在第一次对外部对象调用访问器时,才会调用内部对象的构造函数,这将使我能够捕获异常,据推测,这将导致整洁的退出。这看起来像是一个可怕的拼凑。
回想一下,我不需要捕捉异常,程序可以随心所欲地终止。这使我的问题与我发现的其他问题不同。我的问题是,为什么没有为成功构建的静态对象调用析构函数?
格雷厄姆。
您缺少的是未处理异常。当程序由于未处理的异常而终止时,不能保证调用本地和静态对象的析构函数(我记得它是由实现定义的(。一种解决方案是将这些对象放在一个通用的包装器对象中,在main
的try
块中创建它,并使指向它的指针可用于当前全局变量的所有任意访问。
草图:
class Drivers
{
friend auto main() -> int;
// ...
};
namespace impl {
Drivers* p_drivers;
} // namespace impl
auto drivers() -> Drivers& { return *impl::p_drivers; }
auto main()
-> int
{
try
{
Drivers drivers;
impl::p_drivers = &drivers;
// ...
return EXIT_SUCCESS;
}
catch( exception const& x )
{
log_failure( x.what() );
}
return EXIT_FAILURE;
}
- 停止cmake target_link_libraries将插件中静态库的两个对象文件链接到静态库本身
- 类的全局对象和静态成员
- CPU 瓶颈;处理具有许多非静态对象的 3D 场景渲染的简单方法
- 将 RTOS 队列对象封装在仅具有静态分配的 IQueue 自定义接口中
- 我可以读取静态对象中的文件.txt吗?C++
- 为什么静态数组成员变量在调用对象的实例后不显示任何内容?
- 链接时,不同静态库中的同一对象文件
- 通过 Gazebo 世界插件将静态对象附加到机器人链接
- 将对象创建为全局/静态对象会崩溃,而本地对象不会崩溃
- 静态分配对象的值初始化
- 内联函数的函数本地静态对象是否在共享对象文件之间共享?
- 将基类分配给派生对象,反之亦然,以C++以及静态和动态对象之间的差异
- 如何正确实例化静态字段 tat 是另一个类对象
- 非静态成员引用必须相对于特定对象
- 如何将对象添加到类中的静态向量
- SFML-对象静态定义
- 派生类没有额外的数据成员;将基对象静态向下转换为派生对象是否安全
- 使用全局对象静态成员时出现seg错误
- 卸载应用程序域不清除C++ COM 对象静态成员
- 为什么我不能将模板化对象静态化为继承树