2

Background

I have a chunk of code with the following characteristics:

  1. IO class which is non-copyable due to a std::ifstream member
  2. Foo class which has a NamedConstructor, that likes to call a copy constructor

Question

Is there a pattern I can use where I keep the NamedConstructor in Foo (or something equivalent), but I still can insert non-copyable members into Foo?

I welcome C++11 features/solutions.

Test Code

#include <fstream>

class IO
{
        std::ifstream  m_ifs;  // due to this instance, IO is not copyable
};

// #define NEXT_LINE_REQUIRES_IO_MC

class Foo
{
#ifdef NEXT_LINE_REQUIRES_IO_MC
        IO  m_io;
#endif

public:
        static Foo NamedConstructor() {
                return Foo();
        }
private:
        Foo() { }
};

int
main( int argv, char* argc[] )
{
        Foo f = Foo::NamedConstructor();
}
kfmfe04
  • 14,936
  • 14
  • 74
  • 140
  • 1
    Did you consider using some smart pointer? – Basile Starynkevitch Sep 11 '13 at 05:05
  • 3
    What you have there should compile fine in C++11, because `ifstream` is moveable, and therefore `IO` should be too. However, I just tested it with MinGW (gcc 4.8), and it apparently does not compile, complaining about a deleted move constructor. If you have the same problem, this is a bug. – Benjamin Lindley Sep 11 '13 at 05:14
  • @BenjaminLindley crap - I think you are right, according to this previous post: http://stackoverflow.com/a/4846927/975129 fwiw, I am using gcc 4.7.3 – kfmfe04 Sep 11 '13 at 05:30
  • @kfmfe04: In the meantime, you should probably go with Basile's suggestion, and use `unique_ptr`. – Benjamin Lindley Sep 11 '13 at 05:31
  • @BenjaminLindley ty, I will try that. btw, the compiler-generated move constructor should give me the correct behavior in my snippet above, right? Since the rhs of the NamedConstructor disappears anyways (maybe even through RVO), I assume I am safe. (I haven't played with move constructors at all...) – kfmfe04 Sep 11 '13 at 05:35
  • Yes, it should do the right thing. – Benjamin Lindley Sep 11 '13 at 05:41

1 Answers1

2

This does not call the copy constructor in C++11, but the move constructor, which is ok:

  • std::ifstream is movable in C++11
  • IO will therefore have a valid compiler generated move-constructor
  • since you did not declare a copy-constructor or move-constructor for Foo, it will have a valid compiler generated move.constructor as well.
  • The return statement in Foo::NamedConstructor will call Foo's move-constructor, not the copy-constructor

However, your test code (with the #ifdef commented out) does not yet compile on gcc 4.8, because it wants to use the deleted std::ifstream(std::ifstream&). This is due to the not yet fully implemented standard library in gcc (see here).

Community
  • 1
  • 1
Arne Mertz
  • 24,171
  • 3
  • 51
  • 90