Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unique_ptr in member initialization list

EDIT: I understand unique_ptr is non-copyable and can be only moved. i do not understand what happens with the initialization list.

Why unique_ptr in member initialization list can work as in the code snipt?

#include <memory>

class MyObject
{
public:
    MyObject() : ptr(new int) // this works.
    MyObject() : ptr(std::unique_ptr<int>(new int)) 
    // i found this in many examples. but why this also work? 
    // i think this is using copy constructor as the bottom.        
    {
    }

    MyObject(MyObject&& other) : ptr(std::move(other.ptr))
    {
    }

    MyObject& operator=(MyObject&& other)
    {
        ptr = std::move(other.ptr);
        return *this;
    }

private:
    std::unique_ptr<int> ptr;
};

int main() {
    MyObject o;
    std::unique_ptr<int> ptr (new int);
    // compile error, of course, since copy constructor is not allowed. 
    // but what is happening with member initialization list in above?
    std::unique_ptr<int> ptr2(ptr); 
}
like image 305
pepero Avatar asked Aug 16 '16 21:08

pepero


2 Answers

In your example, std::unique_ptr<int>(new int) is an rvalue, so the move-constructor of ptr is used.

The second time (in main), std::unique_ptr<int> ptr2(ptr) doesn't work because ptr is an lvalue, and cannot be moved directly (you can use std::move).

like image 138
Nelfeal Avatar answered Oct 20 '22 19:10

Nelfeal


This is to do with named and unnamed objects.

When you do this:

std::unique_ptr<int> ptr(new int);
//                   ^^^--- name is 'ptr'

But when you do this:

std::unique_ptr<int>(new int);
//                  ^--where is the name??

If an object is created without a name it is called a temporary or an r-value and the compiler has different rules for r-values than it does for named objects or l-values.

Named objects (l-values) can only be copied to another object but unnamed objects (r-values) can either be copied or moved.

In your example you use a std::unique_ptr. These objects can only be moved because they have had their copy semantics disabled. This is why your compiler is giving an error when you try to copy one:

std::unique_ptr<int> ptr (new int);
// compile error, copy constructor delete
std::unique_ptr<int> ptr2(ptr); // copy is disabled!!

Here ptr is a named object so it can only be copied but its copy semantics are disabled so the whole operation is illegal.

BUT when you do a similar thing with an unnamed object like this:

MyObject() : ptr(std::unique_ptr<int>(new int)) 
                                     ^--- look no name!!!

Then the compiler can either copy or move and it always tries to move before trying to copy.

The std::unique_ptr is fully move complaint so the compiler has no complaints.

like image 38
Galik Avatar answered Oct 20 '22 19:10

Galik