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

constexpr函数能否返回局部对象指针?为何符合C++14要求可编译?

constexpr函数能否返回局部对象指针?

首先直接给结论:在C14标准下,你可以声明一个返回局部对象指针的constexpr函数(只要语法符合要求),但这样的函数几乎没办法在合法的常量表达式上下文里使用。我们结合你给出的代码和C14的规则来拆解:

先看C++14对constexpr函数的要求

根据标准,constexpr函数需要满足这些条件:

constexpr函数必须满足以下要求:

  • 不能是虚函数
  • 返回类型和所有参数必须是LiteralType
  • 存在至少一组参数值,使得函数调用可作为核心常量表达式(core constant expression)的求值子表达式(构造函数只需可用于常量初始化即可),此违规无需诊断。

函数体必须是删除、默认,或仅包含除以下之外的语句:

  • asm声明
  • goto语句
  • case和default之外的带标签语句
  • try块
  • 非LiteralType变量的定义
  • 静态或线程存储期变量的定义
  • 未初始化的变量定义

为什么你的func1能被声明为constexpr?

先看你的代码:

constexpr int * func1 (int a) { int b = 4; return &b; } 
int main() { 
    constexpr int * a = func1(3); 
    int arr[*a]; 
    std::cout << a << std::endl; 
}

对照上面的规则一条条看:

  • func1不是虚函数:符合要求。
  • 返回类型int*和参数int都是LiteralType:int是标量类型,指向标量类型的指针也属于LiteralType,满足条件。
  • 函数体内容:只定义了一个初始化过的int变量(属于LiteralType),然后返回它的地址,没有使用任何被禁止的语句,语法完全合规。

至于标准里提到的“存在至少一组参数让函数调用成为核心常量表达式”,标准明确说了这个违规不需要编译器诊断——也就是说,哪怕你的func1实际上没有任何参数能让它在编译期合法求值,编译器也不会因此拒绝它作为constexpr函数的声明。

关于“编译时获知局部变量地址”的误区

这里你可能被编译器的行为误导了:

  1. 本质上,编译期根本无法获知局部变量的地址。局部变量属于自动存储期,每次函数调用时才会在栈上分配内存,栈的位置在运行时才确定,编译期不可能提前知道它的地址。
  2. 你的代码里constexpr int *a = func1(3);其实是不符合标准的——因为func1(3)返回的是局部变量b的地址,这不属于核心常量表达式,不能用来初始化constexpr变量。但GCC 6.4.0可能做了扩展,或者没有严格执行这个标准检查,允许代码编译。
  3. 你代码里的int arr[*a];能编译,是因为GCC支持C99的变长数组(VLA)作为扩展,这里*a是运行时的值,数组大小在运行时确定,并不是真的在编译期用常量表达式计算出来的。

简单来说:func1能被声明为constexpr是因为它符合语法要求,但它并不能真正在编译期求值返回合法的常量地址,你看到的编译通过其实是编译器的非标准行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:26:50