C++深拷贝机制中operator=实现:为何拷贝构造可用但赋值运算符失效?
问题解答
核心差异
拷贝构造函数和拷贝赋值运算符的运行场景本质不同,是你遇到问题的核心原因:
- 拷贝构造函数在创建全新对象时触发,此时对象的
m_name指针还没有指向任何堆内存,你直接为其分配新内存存储拷贝内容即可,无需处理旧有资源 - 拷贝赋值运算符作用于已经完成初始化的已有对象,此时
m_name已经指向了之前分配的堆内存,你没有先处理原有内存就直接赋值,自然会出现各类问题
错误写法分析
你注释掉的尝试写法都有明确的问题:
m_name = p.m_name:纯浅拷贝,两个对象的m_name指针指向同一块堆内存,两个对象析构时会先后释放同一块内存,触发double free崩溃- 直接执行
m_name = new std::string(*p.m_name):没有释放当前对象原有m_name指向的旧内存就直接覆盖指针,造成内存泄漏 - 尝试分配
std::string数组的写法完全错误:你需要的是单个std::string对象,分配数组的操作和后续析构用delete(而非delete[])的逻辑不匹配,直接触发未定义行为 - 数组循环拷贝逻辑错误:把单个
std::string指针当成数组处理,属于越界访问,运行结果完全不可预期
正确实现
最简单的正确写法如下:
Person& operator=(const Person& p) { if (&p == this) return *this; // 先释放原有内存 delete m_name; // 深拷贝新内容 m_name = new std::string(*p.m_name); return *this; }
如果需要更高的异常安全性(避免new失败时不会破坏当前对象的原有内容),可以使用copy-and-swap写法:
class Person { // 类内新增swap友元 friend void swap(Person& a, Person& b) noexcept { std::swap(a.m_name, b.m_name); } public: // 原有其他函数保持不变 Person& operator=(Person p) { // 传值参数自动完成拷贝构造 swap(*this, p); return *this; } };
内容的提问来源于stack exchange,提问作者Sam Smith
相关产品推荐
相关产品推荐

