分段错误和RAII

时间:2014-09-11 07:16:04

标签: c++ exception segmentation-fault posix raii

这更像是一种哲学类型的问题。

C ++ 中,我们有很好的闪亮成语 - RAII 。但我常常认为它不完整。它与我的应用程序可以使用 SIGSEGV 杀死的事实不符。

我知道,我知道,这样的程序是格式错误你说。但令人遗憾的是,在POSIX(特别是Linux)上,您可以分配超出物理内存限制并在执行过程中遇到 SIGSEGV ,使用正确分配的内存。

你可能会说:"应用程序死了,你为什么要关心那些没有被调用的糟糕的析构函数?"。遗憾的是,有些资源在应用程序终止时不会自动释放,例如文件系统实体。

我现在很厌倦设计黑客,打破良好的应用程序设计只是为了应对这一点。所以,我要问的是为这种问题提供一个漂亮,优雅的解决方案。

修改

似乎我错了,Linux应用程序被内核寻呼机杀死了。在这种情况下,问题仍然是相同的,但申请死亡的原因是不同的。

代码段:

struct UnlinkGuard
{
    UnlinkGuard(const std::string path_to_file)
        : _path_to_file(path_to_file)
    { }

    ~UnlinkGuard() {
        unlink();
    }

    bool unlink() {
        if (_path_to_file.empty())
            return true;

        if (::unlink(_path_to_file.c_str())) {
            /// Probably some logging.
            return false;
        }

        disengage();
        return true;
    }

    void disengage() {
        _path_to_file.clear();
    }

private:
    std::string _path_to_file;
};

void foo()
{
    /// Pick path to temp file.
    std::string path_to_temp_file = "...";

    /// Create file.
    /// ...

    /// Set up unlink guard.
    UnlinkGuard unlink_guard(path_to_temp_file);

    /// Call some potentially unsafe library function that can cause process to be killed either:
    ///  * by a SIGSEGV
    ///  * by out of memory
    /// ...

    /// Work done, file content is appropriate.
    /// Rename tmp file.
    /// ...

    /// Disengage unlink guard.
    unlink_guard.disengage();
}

成功后我使用文件。失败时我希望丢失此文件。

如果 POSIX 支持文件描述符之前未链接的文件link(),则可以获得此功能,但是没有这样的功能:(。

2 个答案:

答案 0 :(得分:5)

  

所以,我要问的是解决这类问题的优秀解决方案。

无,对于C ++和其他语言都不存在。你在这里遇到了一个基本的物理现实,而不是一个设计决定:当用户拔出插头时会发生什么?没有任何编程解决方案可以防范这种情况(好吧,重启时还原)。

可以做的是抓住POSIX信号,有时你甚至可以处理它们 - 但它很有趣,并且有很多警告,another discussion on Stack Overflow details

在段错误之后,不应该清除大多数资源。如果你想要这样做,只需在全局数组trap SIGSEGV中收集这些资源(或者更确切地说,清理处理程序),迭代处理程序中的清理例程数组(希望相关内存仍然完好无损) ),并执行清理。

更具体地说,对于临时文件,它有助于在系统的一个临时文件夹中创建它们。据了解,这些并不总是被各自的应用程序清理干净,系统或用户都会定期执行清理工作。

答案 1 :(得分:3)

通常,无论语言或操作系统如何,解决方案都是在启动程序时清理,而不是(仅)在终止时清理。如果您的程序可以创建在关机时清理的临时文件,那么在启动程序时也要清理临时文件。

当应用程序死亡时,操作系统会杀死大多数其他内容,如文件句柄,tcp连接等。