【问题标题】:How to handle object destruction in error case vs. non-error case如何在错误情况与非错误情况下处理对象破坏
【发布时间】:2011-08-25 18:49:50
【问题描述】:

我有一个程序负责读取数据、格式化数据和创建记录,以及将记录输出到文件。本次讨论的重要类是:

  • RecordGenerator - 包含控制主流程的线程 (获取数据、格式、输出)
  • FileManager - 管理输出文件。记录发送到此 然后将其放入计费文件中。
  • OutputFile - 包含记录的文件的抽象,具有 print()、close() 等。这些对象归FileManager 所有

在正常的进程关闭期间,这些类的析构函数都会被调用,这会导致所有剩余的记录被刷新到当前输出文件,然后它被关闭。这确保我们不会丢失任何数据。 但是,在错误情况下,我们需要关闭但我们不想刷新和关闭文件,因为数据可能已损坏。通常发生的情况是会抛出一个异常,该异常会在RecordGenerator 中被捕获,然后决定这是否是致命错误。如果是,它将启动应用程序关闭。此时FileManager 被破坏,但需要知道是否有错误。同样,当FileManager被破坏时,这会导致OutputFile被破坏,这也需要知道是否有错误。

我的第一反应是添加一些为这些类设置错误标志的公共函数,所以RecordGenerator 可以调用FileManager::setErrorFlag(),然后可以调用OutputFile::setErrorFlag()。添加这些链对我来说似乎是一种非常难闻的气味,特别是如果您认为对象链可能比这长得多。

有没有更好的方法来处理这种情况?

【问题讨论】:

    标签: c++ error-handling destructor raii


    【解决方案1】:

    当人们开始使用 RAII 时,这是一个典型的问题。析构函数应该清理资源并恢复他们负责的任何事情。他们应该提交更改。典型的异常安全 C++ 代码如下所示:

    • 分配资源
    • 做点什么
    • 提交更改

    例如:

    X& X::operator = (const X& x)
    {
        X y(x); // allocate
        this->swap(y); // commit
        return *this;
    }
    
    void f()
    {
        Transaction t(...); // begin transaction
        // operate
        t.commit(); // commit transaction
    }
    
    void g()
    {
        File f(...); // open file
        // write to file
        f.flush(); // flush the buffers, this may throw but not f.~File()
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多