std::shared_ptr的.get()是否复制对象?相关未定义行为探讨
场景1:原始指针指向shared_ptr管理的对象
先看以下代码:
#include <iostream> #include <memory> using namespace std; class myClass{ public: int a = 15; myClass(int x): a(x){}; ~myClass(){cout << "die die ";}; }; int main() { myClass* c; { std::shared_ptr<myClass> a = std::make_shared<myClass>(16); cout<< a.use_count(); //1 std::shared_ptr<myClass> b = a; cout<< a.use_count(); //2 c = a.get(); cout<< a.use_count(); // still 2 } // die die cout << (*c).a; // 16? UB? return 0; }
关键分析:
std::shared_ptr::get()仅返回智能指针管理的原始指针,不会复制对象,因此引用计数不会变化。- 代码块结束时,
a和b的生命周期结束,引用计数降为0,对应的堆对象被析构(输出"die die")。此时c指向的内存已经被释放,后续访问(*c).a属于未定义行为——你可能碰巧读到旧值,但这完全不可靠,程序随时可能崩溃。 - 若执行
delete c,会导致重复释放已被智能指针回收的内存,直接引发程序崩溃,这类操作风险极高,绝对禁止。
场景2:对象赋值(从shared_ptr管理的对象复制)
再看补充场景的代码:
int main() { myClass c(5); { std::shared_ptr<myClass> a = std::make_shared<myClass>(16); cout<< a.use_count(); //1 std::shared_ptr<myClass> b = a; cout<< a.use_count(); //2 c = *(a.get()); // 写法粗糙,但这是在复制对象吗? cout<< a.use_count(); // still 2 }// die die cout << (c).a; //16 return 0; }// die die
关键分析:
c = *(a.get())是对象赋值操作:它将智能指针管理的堆对象的内容,复制到栈上的c对象中(调用类的默认赋值运算符,因为未自定义)。- 这种操作是安全的:栈上的
c和智能指针管理的堆对象是两个完全独立的实例。代码块结束时堆对象被析构(第一次输出"die die"),程序结束时栈对象c被析构(第二次输出"die die"),两次析构针对不同对象,无任何冲突。 get()在这里仅用于获取堆对象的原始指针,进而解引用得到对象本身,赋值操作完全独立于智能指针的管理逻辑,不会影响引用计数。
内容的提问来源于stack exchange,提问作者Ivan
相关产品推荐
相关产品推荐

