我应该把文件的末尾写在析构函数中吗

Should I write the end of the file in the destructor?

本文关键字:析构函数 文件 我应该      更新时间:2023-10-16

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

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标记写入文件。在这种情况下,最佳做法是什么?

吞下异常通常是"最糟糕的做法",因为它一开始就违背了抛出的目的。

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

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

在未来,C++可能会更好地支持事务。但就目前而言,你的做法是合理的。在任何情况下,这就是指定std::filebuf的析构函数的工作方式:

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

你要结束什么?通常,必须在销毁之前关闭打开进行写入的文件(std::ostreamFILE*或系统相关的文件描述符),以便在关闭后检查错误并报告错误。然而,也有例外,特别是包装打开文件的类通常应该在其析构函数中关闭该文件(不检查错误,因为您对此无能为力),以确保在出现异常时进行正确的清理。

据推测,关闭前出现异常意味着已经出现错误,并且将不会使用正在写入的文件。我通常使用commit函数将输出封装在类中。commit关闭并检查错误。如果在commit之前调用析构函数,它将关闭,而不检查错误,然后删除正在写入的文件,因为它可能不完整或不可用。