c++ - 使用 constexpr 返回指针

标签 c++ c++20 constexpr

从 C++20 开始,我们可以在编译时分配内存,我们必须在编译时释放它。因此,这对我提出了一些问题:
首先为什么这有效?

constexpr int* return_ptr() {
    return new int{ 1 };
}

void call_return_ptr(){
    int* int_ptr = return_ptr();
}

int main() {
    call_return_ptr();
    return 0;
}
我正在使用从 constexpr 返回的 ptr而不是在编译时释放它。根据我的理解,这应该是一个错误。
其次,如果第一个示例有效,那么为什么这不起作用:
constexpr int* return_ptr() {
    return new int{ 1 };
}

void call_return_ptr(){
    constexpr int* int_ptr = return_ptr();
}

int main() {
    call_return_ptr();
    return 0;
}
即使我们在编译时尝试删除指针,如下所示:
constexpr int* return_ptr() {
    return new int{ 1 };
}

constexpr void call_return_ptr(){
    constexpr int* int_ptr = return_ptr();
    delete int_ptr;
}

int main() {
    call_return_ptr();
    return 0;
}
这仍然是一个错误。这里发生了什么?
- -编辑
Nicol Bolas 对我的问题的第一部分和第二部分给出了非常好的和深刻的回答,但这仍然说明为什么第三个版本(call_return_ptr 也是 constexpr 的版本)不起作用。根据对 Nicol Bolas 的回答的评论,我仍然不清楚,为什么即使我们将第三个版本的函数签名更改为 consteval由于 call_return_ptr 中的所有内容,仍然会出现错误应该在 constexpr语境。

最佳答案

没有“编译时”这样的东西。并不真地。
什么是“常量表达式评估”。这些是特定类别的表达式,其求值以某种方式发生,因此它们的求值结果可用于源代码。
一个 constexpr function 是一个可以在常量表达式求值期间求值的函数。如果在常量表达式上下文之外调用它,则它不会进行常量表达式求值。constexpr 的初始化器(或 constinit )变量是一个常量表达式上下文。因此,它必须经过常量表达式求值。
常量表达式内存分配规则仅适用于在常量表达式上下文中调用函数时。所以你的第一个 call_return_ptr电话return_ptr并将结果存储在运行时变量中。这不是一个常量表达式上下文;这只是正则表达式评估。该函数分配内存并返回一个指针,就像任何其他函数一样。
您的第二个版本使用该调用的结果 return_ptr初始化 constexpr多变的。这是一个常量表达式上下文......直到变量完成初始化。看,你调用call_return_ptr在常量表达式上下文之外,因此作为常量表达式上下文的函数的唯一部分是 constexpr 的初始化多变的。其他一切,包括 delete call 不是常量表达式上下文的一部分。
所以除非你在常量表达式上下文中调用这个函数,否则你会得到一个编译错误,因为常量评估产生了一个指向 constexpr 分配的内存的指针,该指针在该常量评估中没有被删除。
如果要确保特定函数始终是常量表达式上下文,则必须声明 consteval .
由于或多或少相同的原因,第三个不起作用:该函数不是在常量表达式上下文中调用的。确实,一个 void函数本身不能在常量表达式上下文中,除非它是 consteval ,因为没有 void 的结果用于不断评估的函数。
此外,通过使内部变量 constexpr ,您已经在函数内创建了一个常量表达式上下文。问题是,不断评估的规则是递归的。常量表达式上下文不得泄漏内存,即使该上下文是在另一个常量表达式上下文中计算的。每个常量表达式上下文都必须遵循这些规则,无论其评估之外的上下文如何。

关于c++ - 使用 constexpr 返回指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68786569/

相关文章:

长度为100的C++循环队列类

c++ - 为什么捕获无状态 lambda 有时会导致大小增加?

c++ - 在 C++20 中,如果宏是 #undef'd,然后又是 #define'd,那么它是否被认为是 "active"?

c++ - Clang 3.7.0 提示类不是文字,因为它不是聚合并且没有 constexpr 构造函数

c++ - static, constexpr, const - 它们一起使用时是什么意思?

c++ - 为什么 constexpr 无法绕过 constexpr 求值?

C++编译错误

c++ - 如何在 Windows Visual Studio 8.0 中使用 SGI Ropes?

c++ - GL_Points 上的 gluUnproject 或从鼠标坐标中查找深度坐标

c++ 20如何制作一个像容器一样的约束元组,它只包含允许的类型和它自己的一个实例