Reputation: 45454
I'd like to use a std::unordered_map<unsigned,std::ofstream>
but failed. Now I wonder whether this is simply impossible, or a compiler issue, or whether I just didn't get it right. The problem is the insertion of another element:
std::ofstream&get(unsigned key, std::unordered_map<unsigned,std::ofstream>&map)
{
auto file = map.find(key);
if(file==map.end()) {
map.emplace(std::make_pair(key,std::ofstream{})); // <-- trouble here
file = map.find(key);
assert(file!=map.end());
}
return file->second;
}
fails with gcc (4.8.1), because std::ofstream
is not copy-constructible.
However, it is move-constructible, so there ought to be a solution, or not? (all I want to insert is a default-constructed std::ofstream
). I tried to add
some std::move()
s, but that didn't help.
I just noted that the above code does compile with clang 3.4. Isn't this wrong?
Upvotes: 3
Views: 976
Reputation: 1
Its not related to GCC compiler either will all others presumably, basic_fstream offers fairly simple operations, on top of this file stream does not have copy operations. The solution is if you want two names to refer to the same file stream, use a reference or a pointer or manipulate file streambufs.
STL uses copy often, the above with emplace
or make_pair
uses copy
little more convenient notation for insert()
. The
result of m[k]
is equivalent to the result of (*(<map>.insert(make_pair(k,V{})).first)).second
, where V
is the mapped
type, so there is no move in there.
Subtle difference to move and copy is that after a copy two objects must have the same value, whereas after a move the source of the move is not required to have its original value. Moves can be used when the source object will not be used again. They are particularly useful for implementing the notion of moving a resource.For the most interesting cases, containers, that moved-from state is “empty.”
There are five situations in which an object is copied or moved: • As the source of an assignment • As an object initialiser • As a function argument • As a function return value • As an exception In all cases, the copy or move constructor will be applied (unless it can be optimized away).
Reckon there is bleak chance to accommodate this in the current standard, that not over aforementioned in your case, could you not use a pointer to the ofstream?, like
unordered_map<int, ofstream*> map1;
map1.emplace(1, new ofstream());
Do you have any idea on other compilers which work with move?
Upvotes: 0
Reputation: 46608
you make a pair first then ask map to construct the pair again and cause the problem
try
map.emplace(key,std::ofstream{});
actually, all you need is
std::ofstream&get(unsigned key, std::unordered_map<unsigned,std::ofstream>&map)
{
return map[key];
}
or remove this function... and use map[key]
because map will construct ofstream
using default constructor if a non-exist key was used, so it should works like your code
Upvotes: 3