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

在constexpr函数中使用new关键字创建对象的可行性及编译错误排查咨询

在constexpr函数中使用new关键字创建对象的可行性及编译错误排查咨询

你好,咱们来好好拆解你遇到的这个问题——你尝试在constexpr上下文中用new创建对象,但碰到了好几个编译错误,先从你的代码和具体报错说起:

首先是你写的代码:

#include <random>

struct Buffer {
    int size;
    int* data;

    constexpr Buffer(int n) : size(n), data(new int[n]) {
        for (int i = 0; i < n; ++i)
            data[i] = i;
    }

    constexpr ~Buffer() {
        delete[] data;
    }

    constexpr int get(int i) const {
        return data[i];
    }

    static constexpr Buffer Create(int n) {
        Buffer buf(n);
        // ...
        return buf;
    }
};

constexpr void test(int d) {
    Buffer b2(d);
}

int main() {
    constexpr Buffer b = Buffer::Create(4);
    constexpr Buffer b2(43); // also does not compile: error: ‘Buffer(43)’ is not a constant expression because it refers to a result of ‘operator new’
    test(rand()); // This is Ok
}

你遇到的编译错误主要有两个:

  • 当创建constexpr Buffer b = Buffer::Create(4);时,编译器报错:
    aa.cpp: In function ‘int main()’:
    aa.cpp:23:39: in ‘constexpr’ expansion of ‘((Buffer*)(& b))->Buffer::~Buffer()’
    aa.cpp:10:36: error: deallocation of already deallocated storage
    10 | constexpr ~Buffer() { delete[] data; }
    
  • 当创建constexpr Buffer b2(43);时,报错:
    error: ‘Buffer(43)’ is not a constant expression because it refers to a result of ‘operator new’
    

核心问题:constexpr与动态内存分配的标准限制

说白了,这都是C++标准对constexpr上下文的内存管理规则导致的:

  • C11到C17版本:完全禁止在常量表达式里用new和delete,这也是第二个错误的直接原因——标准明确规定,常量表达式不能依赖operator new的结果。
  • C++20及之后:虽然放开了一点限制,允许在constexpr里用动态内存,但规则特别严:在同一个常量表达式求值过程中分配的内存,必须在这个表达式求值结束前完全释放。也就是说,你绝对不能让一个constexpr对象持有编译时分配的动态内存,因为这部分内存的生命周期只在编译阶段,而constexpr对象会活到运行时,这就会导致内存访问的矛盾。

再看你代码里的具体问题:

  1. 重复释放的错误:在Create函数里,你创建了局部的Buffer buf(n);然后返回它。在C17之前会触发拷贝构造,原对象的析构函数先释放内存,返回的对象析构时又会释放同一块内存;就算C17的NRVO优化避免了拷贝,constexpr对象的析构会在编译时执行,而你想让这个对象把内存带到运行时,这违反了C++20的限制,所以编译器报了重复释放的错。
  2. test(rand());能跑的原因:这里test虽然是constexpr函数,但你是在运行时上下文调用它的(rand()的结果是运行时才确定的),所以new和delete都是普通的运行时操作,完全符合常规的内存管理规则,因此不会报错。

可行的替代方案

如果你需要在编译时搞类似的缓冲区,给你两个思路:

  • 用std::array代替动态分配:如果缓冲区大小是编译时已知的,std::array对constexpr非常友好,完全符合常量表达式的要求。
  • 要是你用的是C++20及以后,非得在constexpr函数里用动态内存,那一定要确保分配和释放都在同一个constexpr表达式里完成,别让持有动态内存的对象离开这个上下文。比如在constexpr函数内部分配内存、处理完就立刻释放,别把带动态内存的对象返回给constexpr变量。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.07 07:08:06