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 ?
Yes. Well the unique ptr has a function object that by default invokes delete on the pointed to object, which calls the destructor. You can change the type of that default deleter to do almost anything.
std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.
An explicit delete for a unique_ptr would be reset() . But do remember that unique_ptr are there so that you don't have to manage directly the memory they hold. That is, you should know that a unique_ptr will safely delete its underlying raw pointer once it goes out of scope.
As for other differences, unique_ptr can handle arrays correctly (it will call delete[] , while auto_ptr will attempt to call delete .
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With