将文件流插入到标准::映射

Insert File stream to std::map

本文关键字:标准 映射 插入 文件      更新时间:2023-10-16

我正在尝试使用文件流实现std::map(实际上是std::p air)。因为标准 c++ 文件流(ifstreams ofstream 和 fstream)不可复制,所以选择落在了 stdioFILE 上。这是最简单的类包装器:

#include <stdio.h>
class FileWriter
{
public:
    FileWriter(const char* fileName)  
    {
        _fs = fopen(fileName, "w");
    }
    ~FileWriter() 
    { 
        fclose(_fs); 
    }
private:
    FILE* _fs;
};

让我们尝试将此类用作 std::map 中的模板参数:

int main()
{
    std::map<int, FileWriter> a{ { 1, FileWriter("fl.fl") } };
}

它编译得很好,但我收到一个运行时错误 - 内存转储。调试器显示析构函数 ~FileWriter() 执行了两次。为什么会发生这种情况以及如何避免此错误?

代码的问题在于复制构造函数只是复制了FILE*,并且在将对象插入std::map<...>时创建了一个临时对象。结果,传入的FILE*得到了fclose() d,并且在尝试访问FILE*时得到了未定义的行为。

在 C++11 中,可以将流emplace()到地图中:

std::map<int, std::ofstream> streams;
streams.emplace(42, std::ofstream("hello, world"));

您使用临时地图创建了地图,该临时地图将复制到地图中需要的位置。由于您没有提供复制构造函数,因此使用默认值,它将简单地复制_fs。 调用临时的析构函数,关闭文件。然后,当地图被销毁时,将在放置在地图中的副本上再次调用析构函数。

您需要为自己的副本构造函数提供适当的语义。但是语义应该是什么?由于某种原因,IO流不可复制。你可以让你的类只移动,但这样你就处于与iostream完全相同的情况,因为它们也是只移动的。

另请参阅:http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29

因为标准 c++ 文件流(ifstreams ofstream 和 fstream)是不可复制的"

是的,因为复制流毫无意义

流不是容器;它们是数据流

不要试图解决这个问题。

构造 FileWriter 类,然后复制到映射中(复制构造)。 这就是析构函数被调用两次的原因。