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 of a Derived object.
1) This one works:
std::unique_ptr<Base> GetDerived() {
return std::make_unique<Derived>();
}
2) But, this one fails to compile:
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 a Base instance, 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?
template<class U> unique_ptr<U> make_unique(U&& value); Returns: A unique_ptr to an object of type U , initialized to move(value) .
make_unique teaches users "never say new / delete and new[] / delete[] " without disclaimers. make_unique shares two advantages with make_shared (excluding the third advantage, increased efficiency).
make_unique is safe for creating temporaries, whereas with explicit use of new you have to remember the rule about not using unnamed temporaries.
Nullability - a scoped_ptr or unique_ptr can be null, a value object can never be. Polymorphism - a value object is always exactly its static type, but you can substitute in different derived types for a unique_ptr. The previously-held object is automatically destroyed when you do this.
std::unique_ptr
is not copyable, only movable. The reason you can return std::make_unique<Derived>
from a function declared to return std::unique_ptr<Base>
is that there is a conversion from one to the other.
So 1) is equivalent to:
std::unique_ptr<Base> GetDerived() {
return std::unique_ptr<Base>(std::make_unique<Derived>());
}
Since the value returned from std::make_unique
is an rvalue, the return value is move-constructed.
Contrast that to 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, the return value must be copy-constructed, and std::unique_ptr
is non-copyable.
works because you cast the lvalue a
to an rvalue, and the return value can be move-constructed.
and 5) work because you already have a std::unique_ptr<Base>
and do not need to construct one to return.
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