【问题标题】:Should I write the end of the file in the destructor?我应该在析构函数中写文件的结尾吗?
【发布时间】:2013-12-20 09:29:51
【问题描述】:

我有一些看起来有点像这样的代码:

void writeToStream( std::ostream & outputStream )
{
    MyXmlWriter xmlWriter{ outputStream };
    xmlWriter.addNode();
    xmlWriter.addNode();
    xmlWriter.close(); // should this be called in `MyXmlWriter` destructor?
}

close 函数会写入一些 xml 关闭标签,以便正确解析文件。构造函数写入 xml 文件的标头。可以考虑xmlWriter.close(); 清理代码。 C++ 将清理代码放入析构函数是常见的建议。这样您就永远不会忘记正确清理。但是,在我们的例子中,清理代码可能会抛出。 (想象file 可以启用异常,写入文件可能会失败。)因此,如果在析构函数中调用close() 函数,那么它应该被包装在一个try-catch 块中,该块会吃掉所有抛出的异常:

MyXmlWriter::~MyXmlWriter() 
{
    try
    {
        close();
    }
    catch (...)
    {
    }
}

但是,在这种情况下,调用者不会收到任何错误通知。函数writeToStream() 可能无法在调用者不知道的情况下将结束 xml 标记写入文件。在这种情况下,最佳做法是什么?

【问题讨论】:

    标签: c++ file-io destructor exception-safety


    【解决方案1】:

    吞下异常通常是一种“最糟糕的做法”,因为它违背了最初抛出的目的。

    但是在这种情况下,您实际上只需要析构函数中的一部分功能,不包括作为“奖励”但可能引发抛出的刷新。尝试刷新可能仍然存在副作用,例如不必要地等待已经发生的网络超时。

    正如 James Kanze 所提到的,最佳实践是在析构函数运行之前手动刷新,这样可以排除析构函数中的异常情况。

    未来 C++ 可能会更好地支持事务。但就目前而言,您的方法是合理的。无论如何,这就是 std::filebuf 的析构函数被指定的工作方式:

    效果: 销毁 basic_filebuf<charT,traits> 类的对象。致电close()。如果在对象销毁期间发生异常,包括对close() 的调用,则会捕获该异常但不会重新抛出(参见 17.6.5.12)。

    【讨论】:

      【解决方案2】:

      你要关闭什么?一般来说,关闭一个打开写入的文件(std::ostreamFILE* 或系统相关的文件描述符)必须在销毁之前完成,以便您可以在关闭后检查错误并报告它们。然而,也有例外,特别是,包装打开文件的类通常应该在它们的析构函数中关闭它(不检查错误,因为你对它们无能为力),以确保在发生例外。

      想必,close之前的一个异常意味着已经有错误了,正在写入的文件将不会被使用。我通常使用commit 函数将输出包装在一个类中。 commit 关闭并检查错误。如果在commit 之前调用析构函数,它会关闭而不检查错误,然后删除正在写入的文件,因为它可能不完整或不可用。

      【讨论】:

        猜你喜欢
        • 2021-10-31
        • 2020-09-25
        • 1970-01-01
        • 2016-03-26
        • 2017-08-30
        • 2015-08-07
        • 2016-09-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多