【问题标题】:Return a dereferenced value of shared_ptr from a function从函数返回一个取消引用的 shared_ptr 值
【发布时间】:2017-06-18 10:10:45
【问题描述】:

这是一个菜鸟问题。下面的代码安全吗?

boost::unordered_set<std::string> func()
{
      boost::shared_ptr<boost::unordered_set<std::string>> list =
              boost::make_shared<boost::unordered_set<std::string>>();

      /* Code to populate the shared_ptr to unordered_set goes here and I do
         populate my set. */

      return *list;
}

首先会发生什么?复制/NRVO/移动或破坏shared_ptr 导致内存故障?如果不安全,我的替代方案是什么?

【问题讨论】:

  • 如果共享指针永远不会被共享,那是没有意义的。这是关于共享指针的问题(在这种情况下,您可能需要扩展您的示例)还是更多的是关于返回值优化的问题?
  • 您也可以拥有boost::unordered_set&lt;std::string&gt; list;return list;,因为您所有的shared_ptr 都在堆上分配了一些额外的东西,除非您共享所有权,否则这对您的情况不是最佳的的shared_ptr 到其他地方。

标签: c++ c++11 boost shared-ptr


【解决方案1】:

发生这种情况:

  • 制作了指向对象的临时副本。这是函数的返回值。副本不能省略。
  • 函数的局部变量,包括共享指针被销毁。
  • 当共享指针被销毁时,引用计数会递减。如果在函数中没有创建共享指针的副本,则 refocount 将达到 0 并且指向的对象被销毁。

这是安全的,但使用动态分配,共享指针似乎毫无意义,如果集合很大,复制的低效率可能会影响性能。


由于您没有证明需要使用指针,我建议使用更简单的替代方法:

boost::unordered_set<std::string> list;

/* Code to populate the unordered_set goes here and I do
     populate my set. */

return list;

NRVO可以应用到this,如果不应用,返回值由move构造。

【讨论】:

    【解决方案2】:

    复制/NRVO/移动或破坏shared_ptr 导致内存故障?

    好吧,让我们考虑一下。考虑这个函数:

    X foo() {
        X x;
        return x;
    }
    

    这里有两个潜在的排序,让我们忘记复制省略。

    1. x 被复制到返回值中,然后x 被销毁。
    2. x 被销毁,然后x 被复制到返回值中。

    (2) 的含义是这样的代码将是未定义的行为,这使得编写函数几乎不可能——因为你不能返回任何局部变量。因此,从语言健全性设计的角度来看,最好是 (1)。


    显式规则在[stmt.return]:

    调用结果的复制初始化在临时对象的销毁之前排序在return语句的操作数建立的完整表达式的末尾,反过来,之前排序 包含return语句的块的局部变量(6.6)的破坏。

    【讨论】:

      【解决方案3】:

      你的 shared_ptr 没有做任何事情,你没有返回它,你正在返回它的内容,即 unordered_set 本身。 您应该更改您的函数以返回 shared_ptr 并按值返回。

      您可能应该使用 std:: 而不是 boost(除非这是一个旧编译器)。

      【讨论】:

      • 我发表了评论说我确实用代码填充了我的 shared_ptr。
      • 但是当您说 *list 时,它会获取共享指针的内容,这就是返回的内容。 shared_ptr 对象本身是在函数的堆栈上本地创建的,并在函数返回时被销毁——它实际上没有写的用途。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-09-05
      • 2013-09-17
      • 1970-01-01
      • 2016-08-27
      • 2017-05-02
      • 2014-01-23
      • 1970-01-01
      相关资源
      最近更新 更多