返回一个shared_ptr的成员变量是否安全

时间:2015-11-08 17:02:23

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

假设我有以下代码,这是我的问题的简化示例:

#include <string>
#include <iostream>
#include <memory>


class A{
  public:
  std::string name() { return "class A"; }
};

class B{
  public:
  B(){
    m_a = std::make_shared<A>();
  }

  std::shared_ptr<A> get_a() { return m_a; }

  private:
  std::shared_ptr<A> m_a;
};

std::shared_ptr<A> foo()
{
  B b;
  return b.get_a();
}

int main()
{
  auto a = foo();
  auto name = a->name();
  std::cout << name;
  return 1;
}

我想知道这样做是否安全?作为B实例的“b”将在函数foo结束时释放。主函数中的“a”是B :: m_a的shared_ptr。 “b”被释放后使用“a”是否安全?

非常感谢提前!

3 个答案:

答案 0 :(得分:5)

foo

shared_ptr<A> foo()
{
  B b;
  return b.get_a();
}

不会返回对b成员的引用,而是返回该成员的标记副本(如果不是RV优化的副本);和shared_ptr a

auto a = foo();

将A堆实例从破坏中保存到范围结束。

因此我认为这是安全的,Bs虽然是创建者,但毕竟只是他们创建和发布的可能许多共享资产的一个用户。

换句话说 - 最后一个关灯,而不是关灯。

live at Coliru

答案 1 :(得分:1)

是的,这很安全。如果这不安全,那么std::shared_ptr将毫无用处。

  

&#34; B&#34;这是B的一个实例将在函数foo结束时释放。

是的,但在此之前复制了std::shared_ptr<A>

让我们看看函数的最后一行是什么:

return b.get_a();

get_a()生成std::shared_ptr<A>,将其复制到临时对象。然后再次复制此临时std::shared_ptr<A>对象,以成为main中呼叫的结果。

(由于返回值优化,实际副本甚至可能被删除,但这并没有改变任何内容。如果有的话,它会使安全性更容易理解。)功能

只有然后b销毁,但其中的std::shared_ptr<A>已经被复制了。

std::shared_ptr<A>中的b实例也被销毁,但A对象的内存未被释放。 这是std::shared_ptr 的重点 - 它知道它被复制的频率,并且仅在最后一个副本被销毁时才释放动态分配的内存。

  

&#34;&#34;在main函数中是一个B :: m_a的shared_ptr。

没有。它是std::shared_ptr<A>,但就是这样。它与原来的B::m_a无关。

  

使用&#34; a&#34;是否安全?之后&#34; b&#34;被释放?

是的,因为ab之间没有持久的关系。

基本上,你质疑安全性是C ++的一个基本特征,即从函数返回值。返回std::shared_ptr与安全无关,而不是返回std::stringint。这总是当你从函数返回值时会发生什么:复制了要返回的值,原始文件被销毁,副本仍然存在。

答案 2 :(得分:0)

这是安全的。

shared_ptr在堆上创建一个跟踪变量。这使得对象B更复杂,因为即使在堆栈上创建它,它也会从堆中分配A。可能影响绩效。

当跟踪数据的所有用户都停止访问时,shared_ptr<>将被删除。