10

I have this map which compiles fine in MSVC10 :

std::map<std::string, std::ofstream> m_logFiles;

But on ubuntu using g++ 4.5 with C++0x enabled, I get the following error message :

/usr/include/c++/4.5/bits/ios_base.h|785|error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private

By using pointers instead of objects, I resolved the problem.
Searching on the web, I learned that streams are not meant to be copied (the why was well explained). But my question is, is std::ofstream a movable type ? If it is, shouldn't it allow its use as a template parameter in the standard containers ?
If yes, then is g++ behind MSVC10 on this point ? (which would explain why it works on MSVC). I know it would be silly to ask compiler writers to fully implement something that isn't even final, but I'm curious regarding the future.

Using g++ 4.6.1 didn't help.

Edit : reading the comments I dug a little bit further and found that the insert is causing the problem, not the declaration of the map.

Reading Cubbi's link I tried the following :

#include <string>
#include <fstream>
#include <map>

using namespace std;

int main()
{
    map<string, ofstream> m_logFiles;
    ofstream st;
    m_logFiles.insert(make_pair<string, ofstream>(string("a"), move(st)));
    return 0;
}

But still no luck. g++ complains about the use of b deleted copy constructor.

Jonathan Merlet
  • 275
  • 3
  • 13
  • The posted code compiles fine in GCC 4.5.3 as well. However, GCC's library (unlike clang's libc++) has not yet implemented map.emplace() http://gcc.gnu.org/bugzilla/show_bug.cgi?id=44436 -- perhaps that's what caused the error message? – Cubbi Aug 15 '11 at 15:39
  • @Cubbi : I read your link and tried using std::move, but no change. – Jonathan Merlet Aug 15 '11 at 16:57

2 Answers2

8

std::ofstream is movable. This program compiles for me using clang/libc++:

#include <string>
#include <fstream>
#include <map>

int main()
{
    std::map<std::string, std::ofstream> m_logFiles;
}

Reference 27.9.1.11 [ofstream.cons].

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 6
    The result on any one compiler (or even many compilers) does not really answer this question. A reference to the spec is needed. – Nemo Aug 15 '11 at 15:26
  • 5
    @Nemo - Howard is the person implementing the standard library for this compiler. I'd trust him. – Bo Persson Aug 15 '11 at 15:30
  • 1
    Check pretty much all of section 27 of the C++0x draft. I didn't find a single place which says "ofstream shall be movable", but it specifies that the stream classes have move constructors and move assignment operators and all the other move-related plumbing. So yes, they're movable, as @Howard said. :) – jalf Aug 15 '11 at 15:34
  • 4
    @Bo: Thanks Bo. Fwiw, I'm also the person who made `osftream` movable. If it isn't, I'm going to be in a really bad mood. :-) – Howard Hinnant Aug 15 '11 at 16:59
  • 1
    @Nemo: Kidding aside, you are quite correct. I've added a reference. – Howard Hinnant Aug 15 '11 at 17:06
  • @Howard : I checked, and yes, the declaration compiles fine, it's in fact the insert that is causing the problem. I tried using std::move, but I don't understand what I'm doing wrong. – Jonathan Merlet Aug 15 '11 at 17:20
  • @Jonathan: I don't think you're doing anything wrong. Your insert compiles for me, and I don't see anything wrong with it. But pair has been thrashed to death, so maybe it isn't up to spec. Try emplace: `m_logFiles.emplace(string("a"), move(st));` – Howard Hinnant Aug 15 '11 at 17:27
  • @Howard : std::map doesn't have the emplace method yet in g++ 4.6.1. Well, I have a workaround and you gave me valuable information, I'll just wait for g++ c++0x support (and its standard library) to continue to evolve. – Jonathan Merlet Aug 15 '11 at 18:39
  • Unfortunately, until g++-4.9 the move constructors are not working for `std::fstream`. Below simple program doesn't compile with g++-4.9, but compiles fine with g++-5: `#include #include struct A { std::fstream m_File; }; int main () { std::vector vA; vA.push_back(A{}); }` Any idea how to fix it for older versions of compilers? – iammilind Sep 23 '15 at 12:19
  • 1
    @iammilind: The only workaround I can think of is `unique_ptr` which will (and should) leave a bad taste in your mouth. :-\ – Howard Hinnant Sep 23 '15 at 16:02
6

I asked a similar question earlier, and later found that GCC doesn't seem to support movable fstreams yet (I just tested GCC 4.6.1) as detailed in this answer.

Community
  • 1
  • 1
Clinton
  • 22,361
  • 15
  • 67
  • 163