如何处理错误情况与非错误情况下的对象破坏

发布于 2024-12-01 08:15:46 字数 808 浏览 5 评论 0原文

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

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

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

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

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

I have a program that is responsible for reading data, formatting it and creating records, and outputting records to files. The important classes for this discussion are:

  • RecordGenerator - contains the thread that controls the main flow
    (get data, format, output)
  • FileManager - manages the output files. Records are sent to this
    class which then puts it in a charging file.
  • OutputFile - abstraction of a file that contains records, has
    print(), close(), etc. These objects are owned by the FileManager

During a normal process shutdown, the destructors for these classes all get called which causes all remaining records to get flushed out to the current output file and then it gets closed. This ensures we don't lose any data.
However, during an error case, we need to shutdown but we don't want to flush and close the file since the data is likely corrupt. Normally what happens is an exception will get thrown which gets caught in the RecordGenerator which then decides if this is a fatal error or not. If it is, it will initiate the application shutdown. It's at this point that the FileManager gets destructed, but needs to know whether there is an error. Likewise, when the FileManager gets destructed, this causes the OutputFile to get destructed which also needs to know whether there is an error.

My first reaction was to just add some public functions that set error flags for these classes, so RecordGenerator could call FileManager::setErrorFlag() which can then call OutputFile::setErrorFlag(). Adding a chain of these seems like a pretty bad smell to me, especially if you consider the object chain could be much longer than this.

Is there some better way of handling this sort of scenario?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

很糊涂小朋友 2024-12-08 08:15:46

当人们开始以不应该使用的方式使用 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()
}

This is a typical problem when people start using RAII the way it's not meant to be used. Destructors should clean resources and revert whatever they are responsible to. They should not commit changes. Typical exception safe C++ code looks like this:

  • allocate resource
  • do something
  • commit changes

For example:

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()
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文