0

I have been reading up on C++11's new move semantics, and what itsn't clear to me is if using a custom constructor prevents the compiler from automatically adding move semantics to your class. I don't understand if the rule of 5 also includes simple classes like the one below.

I have the following class:

class CodeFile
{
private:
    std::vector<Function> functions;
    //std::vector<std::wstring, unsigned long> variables;
    std::vector<std::wstring> lines;
    std::vector<unsigned char> constants;

public:
    std::wstring directory;
    std::wstring fileName;

    void setFilePath(std::wstring filePath);
    bool addFunction(Function function);
    void Run();
    void Finalize();

    CodeFile(std::wstring filePath);
};

With the last line being the constructor. Does defining this constructor prevent the compiler from optimizing the class by adding move constructors?

Should I declare the class as following instead?

class CodeFile
{
private:
    std::vector<Function> functions;
    //std::vector<std::wstring, unsigned long> variables;
    std::vector<std::wstring> lines;
    std::vector<unsigned char> constants;

public:
    std::wstring directory;
    std::wstring fileName;

    void setFilePath(std::wstring filePath);
    bool addFunction(Function function);
    void Run();
    void Finalize();
    static CodeFile fromFile(std::wstring filePath);
};
user2073973
  • 564
  • 6
  • 21

2 Answers2

3

You have no need to do anything here. C++ will write your move constructor for you.

However, whenever you are worried about this, simply add

CodeFile(CodeFile &&)=default;
CodeFile(CodeFile const&)=default;
CodeFile& operator=(CodeFile &&)=default;
CodeFile& operator=(CodeFile const&)=default;

and possibly

CodeFile()=default;

This is a bit of annoying boilerplate, but it is also harmless and expresses that you want the class to be copyable and movable (or you are in insanely generic code and want its copy/movability to dependon its parents and content).

Note you shouldn't have a non-explicit one-argument construtor unless it is a true conversion. So consider explicit on CodeFile(std::wstring).

However, anything that disables the automatic writing of CodeFile(CodeFile&&) also disables the automatic writing of CodeFile(CodeFile const&). So if you find you can no longer copy it, you can also no longer move it (unless you wrote CodeFile(CodeFile const&) manually, which of course disables CodeFile(CodeFile&&) without disabling itself.).

To diagnose things like this, I usually write noisy:

struct noisy {
  noisy(){std::cout << "ctor()\n";}
  noisy(noisy&&){std::cout << "ctor(&&)\n";}
  noisy(noisy const&){std::cout << "ctor(c&)\n";}
  void operator=(noisy&&){std::cout << "asgn(&&)\n";}
  void operator=(noisy const&){std::cout << "asgn(c&)\n";}
  ~noisy() {std::cout << "~\n"; }
};

which does nothing but make noise.

We then write a toy type:

struct Foo {
  Foo (int) {}
  noisy _;
};

with the properties we care about.

A little bit of testing:

Foo f(7);
f = Foo(3);
Foo f2=std::move(f);

demonstrates that the move constructors are fine. Only the default constructor has been stripped from Foo by our writing of Foo(int).

live example.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • So why user-defined ctor prevent [implicitly-declared move constructor](http://en.cppreference.com/w/cpp/language/move_constructor#Implicitly-declared_move_constructor)? – songyuanyao Oct 21 '16 at 14:47
1

Should I declare the class as following instead? ...

No. Just declare the constructors you need automatically generated as follows

CodeFile(CodeFile&&) = default;
πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190