Looks like std::make_unique is making extra copy(related post) while it is supposed to be more efficient. Below is a sample implementation with typical c polymorphic class architecture. The output mentioned below the code snippet shows if we uncomment the call to make_unique, it calls an extra pair of ctor/dtor.
class Shape
{
public:
Shape() { cout << "Shape::ctor\n"; }
virtual ~Shape() {cout << "Shape::dtor\n";}
};
class Rectangle : public Shape
{
public:
Rectangle() {cout << "Rectangle::ctor\n";}
virtual ~Rectangle() {cout << "Rectangle::dtor\n";}
};
unique_ptr<Shape> makeShape(int type)
{
//unique_ptr<Shape> spShape = make_unique<Shape>(); //extra ctor call
unique_ptr<Shape> spShape(nullptr);
switch (type)
{
case 1: //rect
spShape.reset(new Rectangle());
break;
default:
break;
}
return spShape;
}
int main(int argc, char const *argv[])
{
auto shape1 = makeShape(1);
return 0;
}
========================== output with make_unique -------------------------- Shape::ctor Shape::ctor Rectangle::ctor Shape::dtor Rectangle::dtor Shape::dtor -------------------------- output w/o make_unique -------------------------- Shape::ctor Rectangle::ctor Rectangle::dtor Shape::dtor --------------------------
make_unique doesn't works with custom deleter. So what is benefit of using it?
CodePudding user response:
The std::make_unique<Shape>() does not create a null unique_ptr. Instead, it is equivalent to this:
unique_ptr<Shape> makeShape(int type)
{
unique_ptr<Shape> spShape(new Shape); //extra ctor call
switch (type)
{
case 1: //rect
// Must destroy old spShape here.
spShape.reset(new Rectangle());
break;
default:
break;
}
return spShape;
}
If you don’t want to create an object, don't use std::make_unique. The purpose of std::make_unique is to construct the object and make the std::unique_ptr in one step.
[make_unique] is supposed to be more efficient [...]
No, it is not. It is supposed to be safer, if you are constructing objects with temporaries. See:
Differences between std::make_unique and std::unique_ptr with new
Cleaned-up code:
I might write it this way:
std::unique_ptr<Shape> makeShape(int type) {
switch (type) {
case 1:
return std::make_unique<Rectangle>();
default:
return std::make_unique<Shape>();
}
}
CodePudding user response:
std::make_unique ... while it is supposed to be more efficient
std::make_unique isn't "supposed to be more efficient". It's a safe and convenient way to create objects in dynamic storage.
Looks like std::make_unique is making extra copy
It's because you're using it wrong. Do this:
switch (type)
{
case 1: // sidenote: don't use magic numbers such as this
return std::make_unique<Rectangle>();
default:
return nullptr;
}
what is benefit of using it?
Some benefits of using std::make_unique<T>() versus using std::unique_ptr(some_bare_owning_pointer) are:
- Exception safety. If exception is thrown after memory was allocated, but before the constructor of
std::unique_ptris entered, then you leak the allocation. There are cases where this doesn't look possible to happen, but it subtly is (especially prior to C 17). - It lets you follow the rules of thumb "write one delete for each new" (write 0 news -> write 0 deletes) as well as "never use an owning bare pointer".
