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

C++ 使用ios_base::register_callback()和ios_base::event检测流关闭,c++,callback,stream,C++,Callback,Stream,我有一个API,它向API用户返回一个唯一的\u ptr。我想知道用户何时完成此流,以便我可以对他们刚刚写入的文件采取进一步的操作。必须关闭该文件,因为分区即将重新装入 这可能是错误的解决方案,但在返回流之前,我注册了一个回调: 现在,告诉回调一点刚刚发生的事情。一个事件是,此事件的触发器之一是流对象的销毁。这对我有用。不过我担心触发回调的另一个条件- 我应该为此担心还是相信没有人会引起 叫什么名字 有没有更好的方法来完成我的任务 进球 下面是我用来测试的源代码(完整、剪切/粘贴),然后是该

我有一个API,它向API用户返回一个
唯一的\u ptr
。我想知道用户何时完成此流,以便我可以对他们刚刚写入的文件采取进一步的操作。必须关闭该文件,因为分区即将重新装入

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

现在,告诉回调一点刚刚发生的事情。一个事件是,此事件的触发器之一是流对象的销毁。这对我有用。不过我担心触发回调的另一个条件-

  • 我应该为此担心还是相信没有人会引起 叫什么名字
  • 有没有更好的方法来完成我的任务 进球
下面是我用来测试的源代码(完整、剪切/粘贴),然后是该程序的输出:

#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;
}

您可以将
ios::event
参数与
erase\u event
进行比较,以检测流破坏。为了防止复制
erase\u事件
处理程序,您可以教会它在
copyfmt\u事件
时对自身进行中性化

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


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

回调直接构建到流中,因此我看不到更好的替代方法。还有,如果你能防范那个角落的案子(不管它多么罕见),我会说去吧。有什么办法可以防范它吗?你是说
copyfmt()
?当用户调用该函数时,状态从一个流转移到另一个流。检查
event
标志是否等于
copyfmt_event
,并根据需要执行任何操作。我认为这并不是真的需要,除非您正在使用需要释放或复制的指针存储(
pword
s)。我不认为检查
copyfmt_event
可以检测到这种情况,由于回调在
copyfmt()
之前和之后使用,并且似乎没有办法区分析构函数和由
copyfmt()
触发的“复制成员之前”调用之间的区别。
void done_callback(std::ios_base::event evt, std::ios_base& str, int idx)
{
    // Do something when the file closes ... and only then.
}
#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