2

I have some code which looks a bit like this:

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

The close function writes some xml close tags so the file can be parsed properly. The constructor writes the header of the xml file. One could consider xmlWriter.close(); clean-up code. It is common advice for C++ to put clean-up code into destructors. This way you can never forget to clean-up properly. However, in our case the clean-up code could throw. (Imagine that file could have exceptions enabled, writes to a file can fail.) Therefore, if the close() function is called in the destructor, then it should be wrapped in a try-catch block which eats all exceptions thrown:

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

However, in this case the caller will not be notified about any errors. The function writeToStream() could fail to write the closing xml tags to the file without the caller knowing about it. What is best practice in this situation?

4

2 回答 2

5

吞下异常通常是一种“最糟糕的做法”,因为它首先破坏了抛出的目的。

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

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

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

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

于 2013-12-20T10:12:26.807 回答
4

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

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

于 2013-12-20T09:38:51.193 回答