关于shared_ptr移动语义的疑问:make_shared赋值后原指针为何仍有效
核心错误理解纠正
你当前的代码完全没有触发shared_ptr的移动语义,make_shared<Test>(*p1)操作和shared_ptr的所有权转移没有任何关系,这是你认知偏差的核心来源。
你的代码实际执行逻辑
make_shared<Test>(*p1)的执行流程如下:
- 第一步:对
p1解引用拿到Test&类型的对象引用,也就是p1当前持有的Test实例本身 - 第二步:以这个实例为参数,调用
Test类的拷贝构造函数(你没有自定义拷贝构造,编译器会生成默认版本),创建一个全新的、独立的Test堆对象 - 第三步:返回指向这个新Test对象的
shared_ptr,赋值给p2
整个过程中p1的所有权没有发生任何变更,它仍然持有原始Test对象的所有权,引用计数始终为1,自然可以正常调用Disp()方法。你可以观察这段代码的运行输出,会出现两次Dest打印,也验证了存在两个独立的Test对象。
正确触发shared_ptr移动语义的写法
如果要实现shared_ptr的所有权转移,需要显式调用移动构造,写法如下:
int main() { Test *p = new Test(); shared_ptr<Test> p1(p); shared_ptr<Test> p2 = std::move(p1); // 显式移动构造,转移所有权 // 此时p1已经被置空,后续访问p1属于未定义行为 // p1->Disp(); // 这句话运行时大概率崩溃 p2->Disp(); }
移动构造执行后,p1会被重置为空,不再持有任何对象的所有权,此时再访问p1就符合你之前的预期,属于非法操作。
额外最佳实践提醒
尽量避免用裸指针初始化shared_ptr,推荐直接使用make_shared创建对象,减少出现重复初始化、double free等问题的概率:
auto p1 = make_shared<Test>(); // 替代Test* p = new Test(); shared_ptr<Test> p1(p);
内容的提问来源于stack exchange,提问作者Nihal Kumar
相关产品推荐
相关产品推荐

