在C++20常量表达式中是否允许比较动态分配对象的地址?
只要内存不泄漏,C++20 就允许在 constexpr 函数中分配堆。然而 GCC 和 Clang 在比较两个动态分配对象的地址是否是一个常量表达式的问题上存在分歧。
以下代码段可以用 Clang 编译,但不能用 gcc 编译。
constexpr bool foo() {
int* a = new int(4);
int* b = new int(4);
bool result = a == b;
delete a;
delete b;
return result;
}
constexpr bool x = foo(); // GCC: error: '(((int*)(& heap deleted)) == ((int*)(& heap deleted)))' is not a constant expression
以下在两个编译器上都可以正常工作
constexpr bool foo2() {
int a = 4;
int b = 5;
bool result = &a == &b;
return result;
}
constexpr bool x = foo2();
我假设为了正确删除动态对象,编译器必须知道指针是否指向相同的对象,所以我假设这是一个 GCC 错误(或尚未完全实现)。谁能证实这个假设?还是我错了?
现场示例在这里。
编辑:奇怪的是,当我通过提供的链接打开实时示例时,它也突然在 gcc 上编译。但是如果我将它复制粘贴到一个新的编译器资源管理器实例,它又会失败。或者,如果我多次重新加载它,它会每隔一次失败一次并每隔第二次编译一次......
回答
这是一个 gcc 错误(#85428)。
[expr.const]/5中没有任何内容会导致 的评估a == b失败为常量表达式。唯一有任何问题的就是关于未定义行为的问题。所以我们可以去看看[expr.eq]看看关于指针比较的内容:
如果至少一个操作数是指针,则对两个操作数执行指针转换、函数指针转换和限定转换,以将它们转换为复合指针类型。比较指针定义如下:
- 如果一个指针代表一个完整对象的地址,而另一个指针代表另一个完整对象的最后一个元素之后的地址,则比较的结果是不确定的。
- 否则,如果指针都为空,都指向同一个函数,或者都代表同一个地址,则它们比较相等。
- 否则,指针比较不相等。
两个指针代表不同的完整对象的地址,都不为空,所以我们落入第三个要点,指针只是比较不相等。这里没有未定义或未指定的行为。
a == b应该只是屈服false。
- @PiotrNycz What does that have to do with the comparing the pointers after both allocations have succeeded?