return 成员变量 shared_ptr 是否安全

Is it safe to return a member variable which is a 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 结束时释放。 main函数中的"a"是B::m_a的shared_ptr。在 "b" 发布后使用 "a" 是否安全?

非常感谢!

那个foo

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

不是 return 对 b 成员的引用,而是该成员的独立副本(副本的副本,如果未进行 RV 优化);和 shared_ptr a

auto a = foo();

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

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

换句话说——最后一个关灯的,而不是开灯的那个。

live at Coliru

很安全。

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

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

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

"b" which is an instance of B will be released at the end of function foo.

是的,但是它的 std::shared_ptr<A> 是在那之前复制的。

让我们看看函数的最后一行到底做了什么:

return b.get_a();

get_a() 产生一个 std::shared_ptr<A>,它被复制到一个临时对象。这个临时 std::shared_ptr<A> 对象然后被再次复制成为 main.

中调用的结果

(由于 return-value 优化,实际副本甚至可能被省略,但这不会改变任何东西。如果有的话,它使安全性更加容易理解。)

只有thenb销毁,但是里面的std::shared_ptr<A>到时候已经被复制了

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

"a" in the main function is a shared_ptr of B::m_a.

没有。这是一个 std::shared_ptr<A>,仅此而已。已经和原来的B::m_a没有任何关系了。

Is it safe to use "a" after "b" is released?

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


基本上,您是在质疑 C++ 的一项基本功能的安全性,即 return 从函数中获取值。就安全性而言,返回 std::shared_ptr 与 return 返回 std::stringint 没有什么不同。当您 return 通过函数的值时总是会发生这种情况:将要 returned 的值被复制,原始值被销毁,副本继续存在。