At first glance, it seems that you can do this:
A (std::unique_ptr<int> data = {new int(10)})
: mData(std::move(data))
{}
Note the use of curly braces (i.e. uniform initialization.) However, this does not work (does not compile,) because the unique_ptr
constructor that accepts a pointer is declared as explicit
, which precludes its use here.
One more thing you can do is this:
A (int * data = new int(10))
: mData (data)
{}
That is, accepting a normal pointer and constructing your member from it. And you won't need to move from it either (the std::move
is still recommended though.)
This one does compile and does work, but it has the fatal flaw that although you are taking over the ownership of the passed in pointer (you are going to delete
it,) you are not showing this behavior in your interface. So, this new interface will be less informative than the previous one.
One more way is to write a shortcut function template, like so:
template <typename T>
std::unique_ptr<T> uptr (T * v)
{
return std::unique_ptr<T>(v);
}
And then, your constructor becomes:
A(std::unique_ptr<int> data = uptr(new int(10)))
: mData(std::move(data))
{}
But in my opinion, this is not much of an improvement.
However, if this particular use case is your whole problem, why not just go ahead and define a default constructor and a single-argument constructor like this:
A ()
: mData (new int (10))
{}
/*explicit*/ A (std::unique_ptr<int> data)
: mData(std::move(data))
{}
This is just more sensible. (Note that putting explicit
there is a good idea and good form, but not related to your problem so I've commented it out.)
Also, your second constructor does not actually move anything. The r-value reference type does not work as you think it does in this case. In short, since data
has a name, it's no longer an r-value, although its type is still r-value reference to something.