C++赋值运算符重载:引用返回vs临时变量?正确实现解析
C++赋值运算符=的正确重载探讨
以仅含单个成员的Tester类为例,分析赋值运算符重载的常见错误与正确实现方式:
示例对比
示例1:临时变量+memcpy的错误实现
class Tester { private: int val; public: Tester(int v = 0) : val(v) {} // 错误的赋值运算符重载 Tester operator=(const Tester& other) { Tester temp(other); // 仅操作临时变量,未修改当前对象*this memcpy(&temp, &other, sizeof(Tester)); return temp; } int getVal() const { return val; } };
测试结果:调用a = b后,原对象a的val值并未改变。
示例2:引用返回+直接赋值成员的正确实现
class Tester { private: int val; public: Tester(int v = 0) : val(v) {} // 正确的赋值运算符重载 Tester& operator=(const Tester& other) { if (this != &other) { // 防止自赋值 val = other.val; } return *this; } int getVal() const { return val; } };
测试结果:原对象能正确获得被赋值对象的成员值,支持链式赋值(如a = b = c)。
问题解答
1. 为何临时变量+memcpy的重载无法正确拷贝数据?
核心问题有两点:
- 未修改当前对象:错误实现中仅将源对象的数据拷贝到临时变量
temp,完全没有对当前对象(*this)的成员进行修改,原对象自然不会有任何变化。 - memcpy的误用:即便补上
memcpy(this, &temp, sizeof(Tester)),这种方式也不符合C++对象模型——它绕过了成员的构造/赋值逻辑,一旦类扩展为包含非POD成员(如std::string),会直接导致未定义行为。此外,返回值为值类型会带来额外的拷贝开销,毫无必要。
2. 重载该运算符的正确高效方式是什么?
推荐两种场景下的实现:
针对无动态资源的简单类
- 返回当前对象的引用(
Tester&),避免额外拷贝,支持链式赋值。 - 先检查自赋值,避免无意义操作。
- 直接逐个赋值成员变量,这是最安全高效的方式,如示例2的实现。
针对含动态资源的类(如指针、容器)
使用拷贝并交换(Copy-and-Swap) idiom,兼顾简洁性、异常安全性和效率:
#include <algorithm> // 用于std::swap class Tester { private: int* val; public: Tester(int v = 0) : val(new int(v)) {} // 拷贝构造函数:深拷贝资源 Tester(const Tester& other) : val(new int(*other.val)) {} // 自定义swap函数,仅交换资源指针 void swap(Tester& other) noexcept { std::swap(val, other.val); } // 赋值运算符:利用传值参数自动完成拷贝 Tester& operator=(Tester other) { swap(other); // 交换当前对象与临时对象的资源 return *this; // 临时对象销毁时自动释放原资源 } ~Tester() { delete val; } int getVal() const { return *val; } };
这种方式通过传值参数自动完成源对象的拷贝,再交换临时对象与当前对象的资源,临时对象销毁时会自动清理原对象的旧资源,既避免了自赋值检查,又能保证异常安全。
内容的提问来源于stack exchange,提问作者EmbeddedDOOD
相关产品推荐
相关产品推荐

