25

I have the following code

class A {
    public:
        A(){}
        ~A(){}
    private:
        std::vector<std::unique_ptr<double> > x;
};

A f() {
    A a;
    return a;
}

int main() {
    A a=f();
    return 0;
}

It does not compile (gcc 4.7), unless I comment out the destructor. Actually, I don't really need this destructor in my code, I just wanted to use it for debug purpose.

However, I don't understand what is happening and I therefore fear I have done something wrong. What is happening here ?

Bérenger
  • 2,678
  • 2
  • 21
  • 42

1 Answers1

32

That is because the presence of an explicitly defined destructor prevents the implicit generation of a move constructor for A.

Per Paragraph 12.8/9 of the C++11 Standard:

If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

— X does not have a user-declared copy constructor,

— X does not have a user-declared copy assignment operator,

— X does not have a user-declared move assignment operator,

X does not have a user-declared destructor, and

— the move constructor would not be implicitly defined as deleted.

Now without a move constructor, to return the value from f() the compiler will try to invoke the implicitly generated copy constructor (which is still being generated for backwards compatibility). However, std::unique_ptr is non-copyable. Hence, the error.

Explicitly defining a move constructor (or declaring one as defaulted, as suggested by juanchopanza in the comments) will fix the problem.

Community
  • 1
  • 1
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • @AndyProwl This comment is irrelevant to the answer, may I ask you where did you get the C++ 11 standard, is it in a book? thank you! – taocp Mar 18 '13 at 20:12
  • Well, you should also add `A&operator=(A&&)` in order to provide move-assignments. – ipc Mar 18 '13 at 20:14
  • @SongWang: You can download the latest draft from [here](http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2012/n3485.pdf), but keep in mind this is recent than the current official Standard (which you can buy from ISO) – Andy Prowl Mar 18 '13 at 20:14
  • @ipc: Actually, not explicitly defining the destructor is what makes most sense here IMO. But yes, if one does not want to follow the Rule of Zero, he should at least follow the Rule of Five. – Andy Prowl Mar 18 '13 at 20:16