【问题标题】:make_shared "evidence" vs default constructmake_shared“证据”与默认构造
【发布时间】:2013-02-02 20:03:22
【问题描述】:

make_shared 为对象和引用计数器分配单个块。因此,使用这种技术有明显的性能优势。

我在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

调试时我在本地查看类似这样的内容(删除了一些行)

-   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 用于对象。这些位置很远。

这是正确的输出吗?我理解正确吗?

【问题讨论】:

    标签: c++ memory-management smart-pointers


    【解决方案1】:

    如果您阅读cppreference's page for make_shared,他们会说:

    此函数为T 对象和shared_ptr 的控制块分配内存,只分配一次内存。相比之下,std::shared_ptr&lt;T&gt; p(new T(Args...)) 声明执行了两次内存分配,这可能会产生不必要的开销。

    所以这是预期的行为,您正确地解释了它。

    当然,这是有道理的; shared_ptr 如何控制您已经分配的对象的分配?使用make_shared,您让它负责分配对象,因此它可以在任何需要的地方分配您的对象空间,就在柜台旁边。

    附录:正如 Pete Becker 在 cmets 中指出的,标准的 §20.7.2.2.6/6 表示鼓励但不要求实现只执行一次分配。因此,不应该依赖您观察到的这种行为,尽管可以肯定地说,如果您始终使用make_shared,您将一无所获。

    【讨论】:

    • 引用的文字没有正确反映要求。 鼓励实现只分配一次内存,但这不是必需的。
    • @PeteBecker 谢谢你,我更新了我的答案,参考了传达你提到的标准。
    • “可以肯定地说,如果您始终使用 make_shared,您将一无所获,一无所获” 几乎,但并非总是如此:stackoverflow.com/questions/32113594/…
    【解决方案2】:

    是的,显示的输出是正确的。

    sp2 的情况下,通过make_shared&lt;&gt;() 创建,有一块连续的内存包含引用计数器和分配的对象。这就是两个地址接近的原因,也是make_shared&lt;&gt;()存在的主要原因之一(只执行一个分配而不是两个)。

    sp的情况下,改为通过new Test()单独分配对象,然后构造shared_ptr对象。 shared_ptr 的构造函数必须为引用计数器发出新的分配。由于这个原因,指向对象的地址和引用计数器的地址是相距遥远的。

    【讨论】:

    • 太棒了 :) 我知道这两种方法之间的区别,但我一直在寻找这些指针的内存地址中的证据。
    • @fen:嗯,你找到了证据:)
    【解决方案3】:

    这是正确的输出吗?

    看起来像。

    std::make_shared 的全部意义在于性能 - 动态内存分配相对昂贵,并且仅仅为了保持引用计数器而进行额外分配可能相当浪费。因此,std::make_shared 为对象和计数器分配了足够大的内存块,然后在该块中的正确位置初始化对象(使用placement new)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-16
      • 1970-01-01
      • 1970-01-01
      • 2016-01-06
      • 2010-09-11
      • 2016-07-23
      • 1970-01-01
      • 2018-10-04
      相关资源
      最近更新 更多