当移动赋值被删除时,拷贝赋值如何处理右值?
问题分析与解答
代码片段
struct S { S() = default(); S(S const&){std::cout << "copy ctor" << '\n';}; S& operator=(S const&) { std::cout << "copy assignment" << '\n'; return *this; } ~S(); }; S createS(){return S{};} // 注:原代码中`return s{}`应为笔误,修正为`return S{}` int main() { S s{}; s = createS(); }
1. main()中赋值操作的实际行为
执行s = createS();时,会调用拷贝赋值运算符,控制台会输出copy assignment。
具体逻辑:
createS()返回的是右值,但我们没有为S定义移动赋值运算符(operator=(S&&))。- 根据C++规则:当类显式声明了拷贝构造、拷贝赋值、析构中的任意一个,编译器不会自动生成移动构造和移动赋值运算符,且这些移动操作会被隐式删除。
- 此时编译器会寻找可匹配右值的赋值运算符,而
operator=(const S&)的参数是const左值引用——C++标准允许右值绑定到const左值引用,因此该拷贝赋值运算符会被选中执行。
2. 右值与左值的绑定逻辑
const左值引用是C++标准特意设计的“可兼容右值的引用类型”,它既可以绑定左值,也可以绑定右值。
从语义上看,拷贝操作仅需要读取被拷贝对象的值,右值虽然无法被修改、复用,但它的值是可读的;const左值引用恰好保证了不会修改引用对象,因此绑定右值完全合法。
如果想让右值触发移动而非拷贝,只需显式定义移动赋值运算符:
S& operator=(S&&) noexcept { std::cout << "move assignment" << '\n'; return *this; }
此时createS()返回的右值会优先匹配移动赋值运算符。
内容的提问来源于stack exchange,提问作者Ali Sedighi
相关产品推荐
相关产品推荐

