【问题标题】:Returning smart pointer from raw pointer从原始指针返回智能指针
【发布时间】:2020-06-01 05:03:59
【问题描述】:

这是我从原始指针返回智能指针的方式。

std::shared_ptr<Geometry> Clone() const
{
    Circle *sc = new Circle(*this);
    return std::shared_ptr< Geometry >(sc);
}

从原始指针返回智能指针是否正确?

【问题讨论】:

标签: c++ c++11 c++14


【解决方案1】:

“正确”一词相当含糊。好的,如果您要求,此代码应该可以工作。但是,您应该考虑更多细节。

首先,最好在构造智能指针的同一表达式中构造对象:

std::shared_ptr<Geometry> Clone() const
{
    return std::shared_ptr< Geometry >(new Circle(*this));
}

为什么会这样?想象一下,您在两者之间再添加一行代码,而这段代码引发了异常……这就是智能指针的好处,它们可以防止您像这样的内存泄漏,而您在初始版本的代码中失去了这种好处。

接下来,我没有看到class Geometry 的定义,它可能有一个虚拟析构函数……但如果没有呢? shared_ptr 会破坏哪个类?答案是:shared_ptr 知道的类。好的,在您的代码中有一种方法可以让 shared_ptr 知道实际类是 class Circle (因为 shared_ptr 构造函数,它确切地知道底层对象的实际类),但是很容易出错. One-liner 解决了这个问题。

但还有一项(可能的)改进:std::make_shared:

std::shared_ptr<Geometry> Clone() const
{
    return std::make_shared< Circle >(*this);
}

在这种情况下,您只为对象和计数器结构分配一次内存。除非您雇用std::weak_ptr,否则效果会更好。使用std::make_sharedstd:weak_ptr 时应该非常小心:共享计数器的实际内存释放(在std::make_shared 的情况下与对象本身使用的内存相同)将仅在最后一个之后完成weak_ptr 被破坏。这可能会导致某种内存泄漏。

所以你使用它的方式是正确的,但是没有足够的信息来判断什么是最好的惯用方式。

【讨论】:

  • @t.niese,尝试回答这个问题:与直接使用std::shared_ptr 构造函数相比,使用std::make_shared 有什么好处?答案是:您可以为对象和控制结构分配一次内存。确保这些内存位置不重叠,但它们位于同一个内存块中。我在回答中添加了有关weak_ptrmake_shared 用法的更多信息。
  • @t.niese,问题真的只出现在这种情况下。但这个问题略有不同。如果第一个shared_ptr 是使用将原始指针传递给已经创建的东西的构造函数创建的——您可能会滥用控制结构的一些内存(几个字节)。但在make_shared 的情况下,这不是“几个字节”,而是对象的大小,这可能是巨大的内存损失。
  • 好的,现在我明白你的意思了。我删除了我的 cmets。
【解决方案2】:

正确的做法是返回如下

return std::make_shared<Geometry>(new Circle(*this));

如果你像这样创建共享指针

std::shared_ptr<Geometry> Clone() const
{
  Circle *sc = new Circle(*this);
  return std::shared_ptr< Geometry >(sc);
}

你最终在内存中分配了两个不是你想要的。

解释:

共享指针有一个包装器,其中包含指针周围的信息,以密切关注引用计数。当您调用 make_shared 时,这两个部分(包装器加上原始指针)保证在同一个内存块中。

不然就是这个样子

+--+      +---------+-------------+--------------  
|sp| ---> | raw ptr | strong refs | weak refs ...
+--+      +---------+-------------+--------------  
                 \
               +---------+
               |  Circle |
               +---------+

但是通过使用 make_shared 代替,它在内存中看起来像这样

+--+      +---------+-------------+--------------  
|sp| ---> | Circle  | strong refs | weak refs ...
+--+      +---------+-------------+--------------  

这样更有效。

【讨论】:

  • 正如我在下面回答的那样,这个解决方案可能有一个缺点。
  • 这个答案是错误的。我建议你删除它,因为如果你修复它,你只会重复@DmitryKuzminov 的回答。
  • @j6t 哪里错了?这是做 shared_ptr 的正确方法
  • 必须是return std::make_shared&lt;Circle&gt;(*this)。没有new 那里。也许你的意思是return std::shared_ptr&lt;Geometry&gt;(new Circle(*this))?但是@DmitryKuzminov 已经提到了所有这些。
猜你喜欢
  • 2016-08-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-22
  • 1970-01-01
  • 1970-01-01
  • 2014-05-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多