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

为何class{}.refmem是左值表达式?右值对象引用成员访问规则解析

关于右值对象访问引用类型成员得到左值的原理

首先明确C++值类别(value category)的核心判定逻辑:表达式的值类别由其本身的属性决定,而非所属对象的生命周期。

1. 成员访问表达式的标准规则

C++标准对成员访问的左值/右值判定有明确规定:

  • 当访问的非静态成员不是引用类型时(比如示例中的S{}.val),表达式的值类别和对象表达式的类别一致:S{}是临时右值对象,因此S{}.val属于xvalue(亡值,右值的子类)。
  • 当访问的非静态成员是引用类型时(比如S{}.rval),该表达式的行为等价于解引用指向引用绑定对象的指针,而解引用指针的结果是左值——因为引用本质是对象的别名,访问引用成员就是获取它绑定的对象,而这个对象(此处为val)本身是左值。

2. 底层逻辑:引用本质与生命周期的区分

你混淆了引用的生命周期和引用绑定对象的生命周期:

  • 临时对象S{}会在当前语句结束时销毁,成员val也会随之消亡,但S{}.rval作为表达式,其语义是返回对val的引用——在表达式求值的瞬间,val仍然存活,而引用类型成员访问的规则就是暴露它绑定的左值对象,不管所属整体是不是临时对象。
  • 换个角度:引用不是独立对象,只是别名。访问rval时,编译器直接将其替换为val的别名,val虽属于临时对象,但本身是可寻址的左值(你可以合法取&S{}.rval,结果就是&val),因此整个表达式自然是左值。

3. 代码示例验证

以下扩展代码能直观体现规则:

struct S {
    int val = 42;
    int& rval = val;
};

int main() {
    // S{}.rval是左值,可直接赋值
    S{}.rval = 100;
    // S{}.val是xvalue(C++17后允许右值赋值)
    S{}.val = 200;

    // 取地址验证:两者都可寻址,但绑定的对象会随临时结构体销毁
    int* p1 = &S{}.rval;
    int* p2 = &S{}.val;
}

注意:虽然S{}.rval是左值,但绑定的val会在语句结束后销毁,后续通过p1访问内存会触发未定义行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 16:33:13