繁体   English   中英

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类除了向Orange声明自己向stdout的构造函数和析构函数外,什么都没有,只是Orange的构造函数随后抛出异常。 在主文件中,我以此顺序定义了Apple,Pear和Orange的一个静态实例。 构造函数在程序执行时被调用,Orange抛出其异常,并且程序结束,而未调用Apple和Pear的析构函数。

我在想什么?

在回答类似问题(例如556655)时,人们建议:-不要在构造函数中抛出异常。 咦? -具有单独的初始化方法,在构造后称为“手动”,以执行可能会失败的任何操作。 那么RAII呢? (顺便说一下,这就是我现在的情况,无一例外)。 -将静态对象更改为指针,并使用new运算符“手动”调用构造函数。 然后,我必须设法在发生故障时调用正确的析构函数,我希望可以避免使用异常。 -将每个静态对象包装在另一个具有访问器功能的对象中,以获取对该对象的引用。 显然,直到第一次在外部对象上调用访问器时,才会调用内部对象的构造函数,这将允许我捕获异常,并且可能会导致整洁的退出。 这似乎是一个可怕的恶棍。

回想一下,我不需要捕获异常,程序可以根据需要终止。 这使我的问题不同于我发现的其他问题。 我的问题是,为什么析构函数不要求成功构建的静态对象?

格雷厄姆。

您缺少未处理异常的信息。 当程序由于未处理的异常而终止时,您不能保证会调用本地和静态对象的析构函数(正如我记得的实现定义)。 一种解决方案是将这些对象放在公共包装器对象中,在maintry块中创建它,然后仅使指向它的指针可用于当前全局变量可能存在的所有任意访问。

草图:

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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM