Setter方法中使用make_shared却表现为创建副本的原因排查
问题分析与解决思路
嘿,这个问题我之前帮好几个开发者排查过,核心问题大概率出在你传递对象的方式和智能指针初始化的逻辑上,咱们一步步拆解:
最可能的错误原因
你大概率是在setPart()方法里做了「对象拷贝」,而不是让智能指针直接指向原对象的内存。举个典型的错误代码例子:
// 假设你的类是这样的 class YourClass { private: std::shared_ptr<Part> m_part; public: // 这里用了值传递,会创建some_part的副本 void setPart(Part some_part) { // 用副本创建了一个新的Part对象,m_part指向这个新副本 m_part = std::make_shared<Part>(some_part); } };
这种情况下,当你把some_part传入setPart()时,参数some_part是原对象的临时副本,之后你用这个副本在堆上创建了一个全新的Part实例,m_part指向的是这个新实例,和你原来的some_part完全是两个独立的对象。所以你修改原some_part的属性时,m_part指向的对象根本不会有变化。
正确的实现方式
要让m_part和原对象同步变化,核心是让智能指针直接指向原对象的内存地址,而不是创建副本。分两种场景处理:
场景1:原对象在堆上(推荐)
如果你的some_part本来就是在堆上创建的,那直接传递智能指针(或者转移所有权,看你用的智能指针类型):
// 用shared_ptr传递,共享所有权 void setPart(std::shared_ptr<Part> part) { m_part = part; } // 调用的时候 auto some_part = std::make_shared<Part>(); yourObj.setPart(some_part); // 此时修改some_part->属性,m_part->属性会同步变化 some_part->name = "new name";
场景2:原对象在栈上(需注意生命周期)
如果some_part是栈上对象,不能直接用智能指针接管(会导致栈对象被智能指针释放,触发double free),这时可以用std::reference_wrapper来持有引用,或者直接存原始引用(但要确保原对象的生命周期比YourClass实例长):
#include <functional> // 要包含这个头文件 class YourClass { private: std::reference_wrapper<Part> m_part; public: void setPart(Part& part) { m_part = part; } // 访问的时候用.get()获取原对象 Part& getPart() { return m_part.get(); } }; // 调用的时候 Part some_part; yourObj.setPart(some_part); // 修改some_part,m_part对应的对象也会变 some_part.name = "new name";
额外注意点
- 如果用的是
std::unique_ptr,它是独占所有权的,传递时需要用std::move转移所有权,比如:
但这种情况下原对象的所有权会转移到void setPart(std::unique_ptr<Part> part) { m_part = std::move(part); }m_part,原unique_ptr会变成空指针,根据你的需求选择。
简单来说,你现在的代码相当于给智能指针塞了个原对象的“双胞胎兄弟”,俩兄弟互不影响;要让它们同步,就得让智能指针直接“绑定”原对象本身。
内容的提问来源于stack exchange,提问作者Louis Etienne
相关产品推荐
相关产品推荐

