You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++23返回右值引用规则放宽的原因及编译问题解析

为何C++23起返回右值引用的规则更为宽松?

以下是最小可验证示例(MCVE):

#include <iostream>

int&& foo() {
    int i = 2;
    return i;
}

int main() {
    std::cout << foo();
}

该代码在C11至C20中无法编译,但在C++23下,gcc和clang仅触发警告并允许编译,而这会导致未定义行为(undefined behavior)。

说明

按值返回可能涉及临时对象的构造与拷贝/移动,除非使用拷贝消除(copy elision)。具体的拷贝/移动条件如下:

规则内容标准版本
从局部变量和参数自动移动
若表达式为(可能带括号的)标识符表达式(identifier expression),指代具有自动存储期的变量,且其类型为
- 非volatile对象类型
(since C++11)
- 或非volatile对象类型的右值引用(since C++20)
且该变量声明于
- 函数或lambda表达式的最内层封闭体中
- 或作为其参数
(since C++11)
若表达式是可移动的,则会执行两次重载决议以选择用于初始化返回值的构造函数:
- 首先将表达式视为右值表达式(因此可能选择移动构造函数);
- 若第一次重载决议失败
(since C11)
(until C
23)
- 或决议成功但未选择移动构造函数(形式上,所选构造函数的第一个参数并非表达式类型(可能带cv限定)的右值引用)(since C11)
(until C
20)
- 则按常规执行重载决议,将表达式视为左值(因此可能选择拷贝构造函数)。(since C11)
(until C
23)
若表达式是可移动的,则将其视为亡值(xvalue)(因此重载决议可能选择移动构造函数)。(since C++23)
保证拷贝消除
若表达式为纯右值(prvalue),则结果对象由该表达式直接初始化。当类型匹配时,这不会涉及拷贝或移动构造函数(详见拷贝消除)。
(since C++17)

我未能理解C20与C23之间的这一差异,曾假设这会为NRVO(具名返回值优化)提供更多优化空间并做了实验,但未得到验证。

我的具体问题如下:

  • 该程序在C++23中是否应当允许编译?
  • 导致该代码在C++23下仅触发警告即可编译的具体规则差异是什么?
  • 引入这一规则差异的理由是什么?

小更新:我刚找到一篇相关论文:P2266R1,尚未阅读。

免责声明:原问题最初发布于某波兰论坛,但该问题始终困扰着我(或许也包括原提问者)。

内容的提问来源于stack exchange,提问作者Marek R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 10:54:55