c++中内置类型赋值运算符返回左操作数的非const左值引用,如a = b的表达式类型为int&(当a是int型时)。

赋值运算符返回左操作数的引用
在 C++ 中,内置类型的赋值运算符(如 int、double、指针等)返回的是左操作数的 非 const 左值引用。比如 a = b 的表达式类型是 int&(当 a 是 时),这使得链式赋值 <code>a = b = c 成立。
自定义类的赋值运算符也应遵循这一约定:返回 *this 的引用,否则会破坏语义一致性,且可能让某些依赖该行为的模板代码(如 STL 容器内部赋值逻辑)出错。
- 必须返回
T&(其中T是当前类类型),不能返回void、const T&或值类型 - 常见错误写法:
void operator=(const T& other)—— 看似“安全”,实则禁用链式赋值且违反标准库预期 - 返回
const T&会导致后续无法继续赋值(如(a = b) = c编译失败),因为 const 引用不能作为左值
为什么不能返回值或 void
返回值(T)会触发一次额外拷贝构造,降低性能;更重要的是,它让表达式变成纯右值,无法被再次赋值或取地址,彻底破坏链式操作能力。返回 void 则直接让 a = b = c 编译不过——因为 a = b 没有值,无法参与下一次赋值。
-
std::vector::assign、std::string::operator=等标准库实现全部返回string&/vector& - 像
std::optional<t>::operator=</t>这类现代容器,也严格保持返回optional& - 如果重载了
operator=却返回void,配合auto x = a = b;会编译失败(auto无法推导void)
移动赋值运算符也要返回引用
移动赋值(operator=(T&&))同样必须返回 T&,而非 void 或 T&&。虽然移动后对象处于有效但未指定状态,但返回引用本身不涉及使用其内容,只是延续语法契约。
- 错误示例:
T&& operator=(T&& other)—— 返回右值引用会导致(a = std::move(b)) = c编译失败(右值不能作为赋值左值) - 正确写法始终是:
T& operator=(T&& other) noexcept { /* ... */ return *this; } - 注意:移动赋值中若需交换资源(如用
std::swap),仍要确保*this在返回前处于可析构/可赋值状态
赋值返回引用的实际影响场景
最常被忽略的是与算法或泛型代码的交互。例如 std::fill(first, last, value) 内部会对每个迭代器解引用后执行赋值,依赖返回值可被忽略(但类型必须合法);而某些自定义算法可能显式使用 if ((x = y)) 这类判断(虽不推荐,但合法)。
- 调试时打印赋值结果:
std::cout —— 若返回 <code>void,这行直接报错 - 宏或模板中隐含依赖:
#define ASSIGN(x, y) ((x) = (y)),后续可能接+=或函数调用 - Clang 和 GCC 对返回
void的赋值重载会发出-Wreturn-type警告,因为违反隐式约定
真正容易被忽略的不是“要不要返回”,而是“返回什么引用”——不是 const T&,不是 T,也不是 void,就是裸的 T&,且必须是 *this。哪怕类里全是 const 成员,只要支持赋值,这个签名就不能妥协。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











