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

C++局部变量生命周期结束后其指针编译时比较的合法性问题

问题描述

从C++17开始,我们可以定义一个constexpr函数,返回其内部局部变量的指针,这样调用方就会得到一个指向已结束生命周期对象的指针。
显然,对这类指针解引用会触发未定义行为,是被禁止的,但对这类指针做相等比较是否合法呢?
参考以下示例代码:

constexpr auto f() {
    char c = 0;
    auto p = &c;
    return p;
};

int main() {
    static_assert( ( f() == f() ) == ( f() == f() ) ); //所有编译器均通过
    static_assert( f() == f() ); //GCC判定为true,Clang判定为false
}

第一个static_assert被所有编译器接受,即使存在未定义行为也没有任何警告,它的作用是验证f() == f()的结果在同一编译器下是一致的,要么始终为true要么始终为false。
GCC认为f() == f()的结果为true,而Clang则判定为false,后者的结果看起来更符合编译期逻辑。
请问上述两种编译器的实现哪一个是符合C++标准的?


解答

Clang的实现符合C++标准,GCC的处理不符合标准要求,原因如下:

  • 首先明确f()的行为:每次调用f()时,函数内部都会创建一个独立的局部char对象c,返回的指针指向该临时对象,调用结束后对象生命周期结束,因此返回值属于悬空指针。
  • 运行期下对悬空指针做任意操作(包括相等比较)都属于未定义行为,但编译期常量求值有额外的语义约束:C++标准要求编译器在常量求值过程中必须追踪指针的来源标识,而不是仅比对地址的数值。
  • 根据C++标准[expr.eq]章节的规定,两个指针相等当且仅当它们指向同一个完整对象、同一个函数,或者同为空指针。每次调用f()生成的局部对象c是完全独立的不同实例,哪怕它们的存储地址数值相同,它们的指针来源标识也不同,因此f() == f()的求值结果应为false。
  • 示例中第一个static_assert全部编译器通过的原因是,它仅验证同一个表达式的求值结果和自身相等,无论f() == f()本身的结果是true还是false,这个断言恒成立。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 23:06:03