C++ 返回共享的成员变量是否安全
假设我有以下代码,这是我问题的简化示例:C++ 返回共享的成员变量是否安全,c++,c++11,shared-ptr,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
#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;
}
#包括
#包括
#包括
甲级{
公众:
std::string name(){return“class A”;}
};
B类{
公众:
B(){
m_a=std::使_共享();
}
std::shared_ptr get_a(){return m_a;}
私人:
std::共享ptr m_a;
};
std::shared_ptr foo()
{
B B;
返回b.get_a();
}
int main()
{
自动a=foo();
自动名称=a->name();
std::cout那foo
shared_ptr<A> foo()
{
B b;
return b.get_a();
}
将堆实例从销毁状态保存到作用域结束
因此,我认为这是安全的,BS,虽然创建者毕竟是一个用户,可能有许多他们创建和发布的共享资产。
换句话说,最后一个人关灯,而不是开灯的人
这是安全的
shared\u ptr
在堆上创建跟踪变量。这使得对象B
更加复杂,因为即使在堆栈上创建对象,它也会从堆中分配a
。可能会影响性能
当跟踪数据的所有用户都停止访问它时,共享的ptr将被删除。是的,它是安全的。如果这不安全,那么共享的ptr将毫无用处
“b”是b的一个实例,将在函数foo结束时释放
是的,但是它的std::shared_ptr
在那之前就被复制了
让我们看看函数的最后一行真正做了什么:
get_a()
生成一个std::shared_ptr
,将其复制到一个临时对象。然后再次复制该临时std::shared_ptr
对象,使其成为main
中调用的结果
(由于返回值优化,实际副本甚至可能被省略,但这不会改变任何事情。如果有任何改变,它会使安全性更容易理解。)
只有到那时,b
才被销毁,但其中的std::shared_ptr
已被复制
b
中的std::shared_ptr
实例也被销毁,但是A
对象的内存没有被释放。这就是std::shared_ptr
的全部要点——它知道它被复制的频率,并且只有在最后一个副本被销毁时才会释放动态分配的内存
主函数中的“a”是B::m_a的共享ptr
不。它是一个std::shared_ptr
,但就是这样。它与原始B::m_a
没有任何关系
释放“b”后使用“a”安全吗
是的,因为a
和b
之间没有持久的关系
基本上,您质疑安全性是C++的一个基本特征,即从函数返回值。返回一个<代码>:ST::SydDypPT/<代码>与返回< <代码> STD::String < /C> >或<代码> int >代码>没有什么不同。当从函数返回值时,总是发生这样的情况:返回。值被复制,原件被销毁,副本继续存在。
可能重复?并且?请发布可编译的代码。例如,没有语法错误,使用正确的main
和\include
s。我已经阅读了这两个问题,但是我决定发布一个新问题,因为我想确保它是安全的(或不安全的)若要执行此操作,则将共享\u ptr作为成员变量的“父”类将超出范围。如果这样做不安全,则我不确定我首先是否理解共享\u ptr的意义。Christian和decltype_auto,您是对的,我只是编辑了代码以使其可编译。
auto a = foo();
return b.get_a();