make_shared 为对象和引用计数器分配单个 block 。所以使用这种技术有明显的性能优势。
我在 VS2012 中做了简单的实验,我在寻找“证据”:
std::shared_ptr<Test> sp2 = std::make_shared<Test>();
std::shared_ptr<Test> sp(new Test());
// Test is a simple class with int 'm_value' member
调试时我在本地 View 中看到了类似这样的内容(删除了一些行)
- sp2 shared_ptr {m_value=0 } [make_shared] std::shared_ptr<Test>
+ _Ptr 0x01208dec {m_value=0 } Test *
+ _Rep 0x01208de0 make_shared std::_Ref_count_base *
- sp shared_ptr {m_value=0 } [default] std::shared_ptr<Test>
+ _Ptr 0x01203c50 {m_value=0 } Test *
+ _Rep 0x01208d90 default std::_Ref_count_base *
似乎sp2分配在0x01208de0(有一个ref计数器)然后在0x01208dec有一个Test对象。位置彼此非常接近。
在第二个版本中,我们有 0x01208d90 用于引用计数器,0x01203c50 用于对象。这些位置很远。
这是正确的输出吗?我的理解正确吗?
最佳答案
如果您阅读 cppreference's page for make_shared
,他们说:
This function allocates memory for the
T
object and for theshared_ptr
's control block with a single memory allocation. In contrast, the declarationstd::shared_ptr<T> p(new T(Args...))
performs two memory allocations, which may incur unnecessary overhead.
所以这是预期的行为,您对其进行了正确的解释。
当然,这是有道理的; shared_ptr
怎么会控制你已经分配的对象的分配?与 make_shared
,你让它负责分配对象,这样它就可以在它想要的任何地方分配你的对象的空间,就在柜台旁边。
附录:正如 Pete Becker 在评论中指出的那样,标准的 §20.7.2.2.6/6 指出,鼓励但不要求实现仅执行一次分配。因此,不应依赖您观察到的这种行为,尽管可以肯定地说,如果您始终使用 make_shared
,您不会有任何损失和收获。 .
关于c++ - make_shared "evidence"与默认构造,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14665935/