使用ios_base::register_callback()和ios_base::event检测流关闭

Using ios_base::register_callback() and ios_base::event to detect stream closing

本文关键字:ios base 检测 event register callback 使用      更新时间:2023-10-16

我有一个API,它向API用户返回一个unique_ptr<ofstream>。我想知道用户什么时候完成这个流,这样我就可以对他们刚刚写入的文件采取进一步的操作。因为要重新挂载一个分区,所以必须关闭该文件。

这可能是这个问题的错误解决方案,但是在我返回流之前,我用register_callback()注册了一个回调:

std::unique_ptr<std::ofstream> os(new std::ofstream(name, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary));
os->register_callback(done_callback, 0);
return os;

回调在别处定义:

void done_callback(std::ios_base::event evt, std::ios_base& str, int idx)
{
    // Do something when the file closes ... and only then.
}
现在,ios_base::event告诉回调函数刚刚发生了什么。其中一个事件是erase_event,该事件的触发器之一是销毁流对象。这对我有用。我关心的是触发回调的另一个条件——copyfmt()。
  • 我应该担心这个还是相信没有人会引起要调用Copyfmt()吗?
  • 有没有更好的方法来完成我的目标?

这是我用来测试的源代码(完整,剪切/粘贴),然后是该程序的输出:

#include <iostream>
#include <fstream>
#include <memory>
void done_callback(std::ios_base::event evt, std::ios_base& str, int idx)
{
    std::cout << "Some sort of stream event occurred. Event: " << evt << std::endl;
}
int main(int argc, char* argv[]) {
    std::cout << "Opening the stream." << std::endl;
    std::unique_ptr<std::ofstream> os(new std::ofstream("test", std::ofstream::out | std::ofstream::trunc | std::ofstream::binary));
    std::cout << "Stream is open." << std::endl;
    std::cout << "Registering callback." << std::endl;
    os->register_callback(done_callback, 0);
    std::cout << "Writing to stream." << std::endl;
    *(os.get()) << "Hello!n";
    std::cout << "Done writing." << std::endl;
    std::cout << "Flushing stream." << std::endl;
    os->flush();
    std::cout << "Done flushing." << std::endl;
    std::cout << "Writing to stream." << std::endl;
    *(os.get()) << "Hello!n";
    std::cout << "Done writing." << std::endl;
    std::cout << "Closing the stream..." << std::endl;
    os->close();
    std::cout << "Stream is closed." << std::endl;
}
输出:

Opening the stream.
Stream is open.
Registering callback.
Writing to stream.
Done writing.
Flushing stream.
Done flushing.
Writing to stream.
Done writing.
Closing the stream...
Stream is closed.
Some sort of stream event occurred. Event: 0

您可以将ios::event参数与erase_event参数进行比较,以检测流破坏。为了防止复制erase_event处理程序,您可以教它在copyfmt_event上阉割自己。

然而,这不是管理文件的好方法。(任何关于安全文件管理的内容对分区来说都是双倍的。)保持文件打开状态的不是fstream对象,而是filebuf对象。标准流对象只处理格式;流缓冲区对象处理I/o

幸运的是,streambuf有一个虚析构函数,因此您可以从std::filebuf派生并在那里添加一些功能。不幸的是,析构函数应该始终是故障安全的,因此它不是挂载文件系统的好地方。您应该只在应用程序的待办事项列表中排队挂载操作。