将文件流插入std :: map

时间:2013-12-31 00:08:40

标签: c++ map filestream destructor

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

#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()执行两次。为什么会发生这种情况以及如何避免此错误?

4 个答案:

答案 0 :(得分:2)

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

您需要为自己的复制构造函数提供适当的语义。但是什么应该是语义? iostream因某种原因无法复制。你可以让你的班级只移动,但那时你和iostream的情况完全相同,因为它们也只是移动。

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

答案 1 :(得分:2)

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

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

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

答案 2 :(得分:1)

  

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

是的,因为复制流没有意义

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

不要试图解决这个问题。

答案 3 :(得分:0)

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