How does the function std :: make_unique <SubClass> work?
I have a base class and its subclass:
class Base { public: virtual void hi() { cout << "hi" << endl; } }; class Derived : public Base { public: void hi() override { cout << "derived hi" << endl; } }; Trying to create a helper function that creates a unique pointer to a Derived object.
1) It works:
std::unique_ptr<Base> GetDerived() { return std::make_unique<Derived>(); } 2) But this cannot be compiled:
std::unique_ptr<Base> GetDerived2() { auto a = std::make_unique<Derived>(); return a; } 3) std :: move works:
std::unique_ptr<Base> GetDerived3() { auto a = std::make_unique<Derived>(); return std::move(a); } 4) If I create an instance of Base, both work:
std::unique_ptr<Base> GetDerived4() { auto a = std::make_unique<Base>(); return a; } std::unique_ptr<Base> GetDerived5() { auto a = std::make_unique<Base>(); return std::move(a); } Why (2) fails, but others work?
std::unique_ptr not copied, but only moves. The reason you can return std::make_unique<Derived> from a function declared to return std::unique_ptr<Base> is the conversion from one to another.
So 1) is equivalent to:
std::unique_ptr<Base> GetDerived() { return std::unique_ptr<Base>(std::made_unique<Derived>()); } Since the value returned from std::make_unique is the value of r, the return value is constructed along the way.
Compare this with 2), which is equivalent to:
std::unique_ptr<Base> GetDerived2() { std::unique_ptr<Derived> a = std::make_unique<Derived>(); return std::unique_ptr<Base>(a); } since a is an lvalue value, the return value must be copied, and std::unique_ptr not copied.
3) works because you impose lvalue a on rvalue, and the return value can be constructed in the process.
4) and 5) work because you already have std::unique_ptr<Base> and you don't need to create one to return.
std::unique_ptr<> does not have a copy constructor, but it does have a move constructor from a linked pointer, i.e.
unique_ptr( unique_ptr&& u ); // move ctor template< class U, class E > unique_ptr( unique_ptr<U, E>&& u ); // move ctor from related unique_ptr The second constructor requires certain conditions (see here ). So why did your code 2 not work, but 4 did? In 4, you did not use any constructor, since the return type was identical to the object, the object itself was returned. In 2, on the other hand, the return type was different and a constructor call was required, but std::move() required for this.
In each case, but (2) the return value was considered as (some) rvalue value. In (2), this is not so because the types did not correspond to implicit displacement.
In a later iteration, standard (2) will also be implicitly moved.
All of them soon enter into undefined behavior after the call, as they try to remove the Derived object with a pointer to Base . To fix this, write down the delete function.
template<class T> using smart_unique=std::unique_ptr<T, void(*)(void*)>; template<class T, class...Args> smart_unique<T> make_smart_unique( Args&&... args ){ return { new T(std::forward<Args>(args)...), [](void*ptr){ delete static_cast<T*>(ptr); } }; } template<class T> static const smart_unique<T> empty_smart_unique{ nullptr, [](void*){} }; These are unique pointers smart enough to handle polymorphism, like shared_ptr .
You will find that std :: unique_ptr can go from derivative to basic if you look at its definition. Basically, here is_convertible checks for this situation.
/** @brief Converting constructor from another type * * Requires that the pointer owned by @p __u is convertible to the * type of pointer owned by this object, @p __u does not own an array, * and @p __u has a compatible deleter type. */ template<typename _Up, typename _Ep, typename = _Require< __safe_conversion_up<_Up, _Ep>, typename conditional<is_reference<_Dp>::value, is_same<_Ep, _Dp>, is_convertible<_Ep, _Dp>>::type>> unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) { }