假设我有以下代码,这是我的问题的简化示例:
#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”是否安全?
非常感谢提前!
答案 0 :(得分:5)
那foo
shared_ptr<A> foo()
{
B b;
return b.get_a();
}
不会返回对b成员的引用,而是返回该成员的标记副本(如果不是RV优化的副本);和shared_ptr
a
auto a = foo();
将A堆实例从破坏中保存到范围结束。
因此我认为这是安全的,Bs虽然是创建者,但毕竟只是他们创建和发布的可能许多共享资产的一个用户。
换句话说 - 最后一个关灯,而不是关灯。
答案 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;被释放?
是的,因为a
和b
之间没有持久的关系。
基本上,你质疑安全性是C ++的一个基本特征,即从函数返回值。返回std::shared_ptr
与安全无关,而不是返回std::string
或int
。这总是当你从函数返回值时会发生什么:复制了要返回的值,原始文件被销毁,副本仍然存在。
答案 2 :(得分:0)
这是安全的。
shared_ptr
在堆上创建一个跟踪变量。这使得对象B
更复杂,因为即使在堆栈上创建它,它也会从堆中分配A
。可能影响绩效。
当跟踪数据的所有用户都停止访问时,shared_ptr<>
将被删除。