std::shared_ptr<Object> p1 = std::make_shared<Object>("foo");
std::shared_ptr<Object> p2(new Object("foo"));

许多谷歌和stackoverflow的帖子都在这里,但我不明白为什么make_shared比直接使用shared_ptr更有效。

有人能一步一步地向我解释创建的对象序列和两者所做的操作,这样我就能理解make_shared是如何高效的。我在上面举了一个例子供大家参考。


当前回答

我发现std::make_shared有一个问题,它不支持私有/受保护的构造函数

std::shared_ptr(new T(args…))如果在可访问的上下文中执行,可能会调用T的非公共构造函数,而std::make_shared需要对所选构造函数进行公共访问。

https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared#Notes

其他回答

我发现std::make_shared有一个问题,它不支持私有/受保护的构造函数

std::shared_ptr(new T(args…))如果在可访问的上下文中执行,可能会调用T的非公共构造函数,而std::make_shared需要对所选构造函数进行公共访问。

https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared#Notes

在前面提到的情况之上,还有另一种情况是两种可能性不同的:如果需要调用非公共构造函数(受保护的或私有的),make_shared可能无法访问它,而带有新变体的可以正常工作。

class A
{
public:

    A(): val(0){}

    std::shared_ptr<A> createNext(){ return std::make_shared<A>(val+1); }
    // Invalid because make_shared needs to call A(int) **internally**

    std::shared_ptr<A> createNext(){ return std::shared_ptr<A>(new A(val+1)); }
    // Works fine because A(int) is called explicitly

private:

    int val;

    A(int v): val(v){}
};

Shared_ptr:执行两个堆分配

控制块(引用计数) 正在管理的对象

Make_shared:只执行一次堆分配

控制块和对象数据。

如果你需要shared_ptr控制的对象上的特殊内存对齐,你不能依赖make_shared,但我认为这是不使用它的唯一一个好理由。

我认为mpark先生的回答中的异常安全部分仍然是一个合理的担忧。当像这样创建shared_ptr: shared_ptr< T >(新T)时,新T可能会成功,而shared_ptr分配控制块可能会失败。在这种情况下,新分配的T会泄漏,因为shared_ptr无法知道它是就地创建的,删除它是安全的。还是我遗漏了什么?我不认为更严格的函数参数计算规则在这里有任何帮助…