Reputation: 1673
I'm trying to implement std::map (actually std::pair) with file streams. Because standart c++ file streams (ifstreams ofstream, and fstream) aren't copyable, choice fell on the FILE from stdio. This is simplest class wrapper:
#include <stdio.h>
class FileWriter
{
public:
FileWriter(const char* fileName)
{
_fs = fopen(fileName, "w");
}
~FileWriter()
{
fclose(_fs);
}
private:
FILE* _fs;
};
Let's trying to use this class as template parameter in std::map:
int main()
{
std::map<int, FileWriter> a{ { 1, FileWriter("fl.fl") } };
}
It compiles well, but I get a runtime error - memory dump. Debugger shows, that the destructor ~FileWriter() performed twice. Why this happened and how to avoid this error?
Upvotes: 3
Views: 1609
Reputation: 154005
The problem with your code is that the copy constructor just copied the FILE*
and a temporary object was created while inserting the object into the std::map<...>
. As a result, the FILE*
passed in got fclose()
d and you got undefined behavior when you tried to access the FILE*
.
In C++11 it is possible to emplace()
streams into a map:
std::map<int, std::ofstream> streams;
streams.emplace(42, std::ofstream("hello, world"));
Upvotes: 3
Reputation: 385295
Because standart c++ file streams (ifstreams ofstream, and fstream) aren't copyable`
Yes, because it makes no sense to copy streams.
Streams are not containers; they are flows of data.
Don't try to work around this.
Upvotes: 1
Reputation: 103741
You created your map with a temporary, which will be copied into the map at the position where it is needed. Since you didn't provide a copy constructor, the default is used, which will simply copy _fs
. The destructor of the temporary is called, closing the file. Then, when the map is destroyed, the destructor will be called again on the copy which was placed in the map.
You need to provide your own copy constructor with appropriate semantics. But what should be the semantics? iostreams are not copyable for a reason. You could make your class move only, but then you're in the exact same situation as the iostreams, as they too are move-only.
See also: http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
Upvotes: 1
Reputation: 652
The FileWriter class is constructed then copied into the map (copy constructed). That is why the destructor is called twice.
Upvotes: 0