std::unique_ptr重赋值时能否先销毁旧值再构造新对象?
解决方案
标准库目前没有内置名为replace_unique的接口,但你可以自行实现一个零开销的工具函数满足需求,核心逻辑就是显式先销毁旧对象,再创建新对象:
#include <memory> #include <utility> template<typename T, typename... Args> void replace_unique(std::unique_ptr<T>& ptr, Args&&... args) { // 第一步:释放旧对象占有的内存 ptr.reset(); // 第二步:构造新对象并赋值 ptr = std::make_unique<T>(std::forward<Args>(args...)); }
使用示例
你原来的refresh_foo函数可以改写为:
void MyClass::refresh_foo(int x) { replace_unique(m_foo, x * 3 + 5); }
如果不想封装函数,直接写两行代码效果完全一致:
void MyClass::refresh_foo(int x) { m_foo.reset(); m_foo = std::make_unique<int>(x * 3 + 5); }
关键说明
- 内存占用符合要求:该实现会先完全释放旧对象的内存,再分配新对象的内存,不会出现两个大对象同时占用内存的情况,生成的汇编代码和你提到的原生指针旧实现几乎没有差异,无额外运行时开销。
- 安全性优于原生指针实现:原生指针版本如果
new阶段抛出异常,m_foo会成为野指针;而该实现中就算make_unique抛出异常,m_foo也只会处于合法的空指针状态,不会出现内存安全问题。 - 异常安全权衡:标准库默认的
operator=和reset采用「先构造新对象、再销毁旧对象」的顺序,是为了提供强异常安全保证:如果新对象构造失败,原指针的内容会完全保留。你需要的优先优化内存的实现只提供基本异常安全保证:新对象构造失败时指针会变为空,你需要确认业务逻辑可以接受这个后果。
内容的提问来源于stack exchange,提问作者Remy
相关产品推荐
相关产品推荐

