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

C++ &运算符重载:取函数返回右值地址合法还是未定义行为?

重载取地址运算符后获取函数返回右值的地址是否合法?

先看问题中的代码:

#include <iostream>

struct Foo {
    int val;
    Foo* operator &() { // 与普通"&"作用一致
        return this;
    }
};

Foo test() {
    return Foo{3};
} 

int main() {  
    Foo* p = &test(); // 为何允许且可运行?
    printf("%d", p->val);
}

核心疑问:通常函数返回值是右值,无法直接取地址,但重载operator&()后代码能编译运行,这属于合法C++语法还是未定义行为?


编译通过的原因:合法的语法扩展

内置的取地址运算符&确实不能作用于纯右值(prvalue),因为纯右值没有实际的内存地址。但当类重载了operator&()成员函数后,&test()的语义发生了变化:

  • 此时&test()不再调用内置运算符,而是调用Foo类的重载成员函数operator&()。
  • C标准允许右值对象调用无引用限定符的成员函数(这里Foo::operator&()没有&或&&限定),编译器会将test()返回的临时Foo对象作为this指针的指向,调用operator&()并返回this指针,这一步完全符合C语法规范。

运行结果的本质:存在未定义行为

虽然代码能编译运行,且在Clang-14、GCC-12中能得到预期结果,但后续通过指针访问临时对象的操作属于未定义行为:

  • test()返回的临时Foo对象是纯右值,其生命周期仅持续到创建它的完整表达式结束——也就是Foo* p = &test();这条语句执行完毕后,临时对象就会被销毁,此时p成为悬垂指针。
  • 你提供的汇编显示编译器将临时对象存储在main函数的栈帧([rbp-16])中,printf执行时该栈空间尚未被覆盖,所以能输出正确值,但这只是编译器的具体实现细节,C++标准不保证临时对象的内存会保留原值,也不保证后续访问不会触发崩溃、输出错误值等问题。

附上你提供的Clang 14汇编输出:

[Clang 14.0.0 无编译参数]
main:                                   # @main
    push    rbp
    mov     rbp, rsp
    sub     rsp, 16
    call    test()
    mov     dword ptr [rbp - 16], eax <---
    lea     rdi, [rbp - 16]           <---
    call    Foo::operator&()
    mov     qword ptr [rbp - 8], rax
    mov     rax, qword ptr [rbp - 8]
    mov     esi, dword ptr [rax]
    movabs  rdi, offset .L.str
    mov     al, 0
    call    printf
    xor     eax, eax
    add     rsp, 16
    pop     rbp
    ret

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 07:45:58