Consider the following code snippets:
std::shared_ptr<Object> p1 = std::make_shared<Object>("foo"); std::shared_ptr<Object> p2(new Object("foo"));
Understanding why make_shared is more efficient than using the shared_ptr constructor directly requires a step-by-step analysis of the operations involved.
make_shared allocates memory only once, while the constructor-initialized shared_ptr allocates memory twice. This makes make_shared more efficient.
In C 17, the evaluation order of function arguments was revised, eliminating an exception safety concern with the constructor-initialized shared_ptr approach. However, let's consider the example:
void F(const std::shared_ptr<Lhs> &lhs, const std::shared_ptr<Rhs> &rhs) { /* ... */ } F(std::shared_ptr<Lhs>(new Lhs("foo")), std::shared_ptr<Rhs>(new Rhs("bar")));
If an exception is thrown during the Rhs constructor, the memory allocated for Lhs will be lost because it was not immediately passed to the shared_ptr constructor. make_shared avoids this issue by eliminating this intermediate step.
However, make_shared has a disadvantage: since it allocates the control block and managed object in a single heap block, the memory for both cannot be deallocated independently. This means that weak pointers can keep the control block alive indefinitely, potentially preventing both the control block and the managed object from being deallocated.
The above is the detailed content of `make_shared` vs. Constructor-Initialized `shared_ptr`: What's the Performance and Exception Safety Difference?. For more information, please follow other related articles on the PHP Chinese website!