比较动态分配对象的地址允许在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 bug(#85428)。

[expr]中没有任何内容。const]/5会导致a == b的求值不是一个常量表达式。唯一有问题的是关于未定义行为的问题。所以我们可以去看[expr]。Eq]来查看指针比较的含义:

如果至少有一个操作数是指针,则在两个操作数上执行指针转换、函数指针转换和限定转换,将它们转换为复合指针类型。比较指针的定义如下:

  • 如果一个指针表示一个完整对象的地址,另一个指针表示另一个完整对象的最后一个元素的后面的地址,则比较的结果是不指定的。
  • 否则,如果两个指针都为空,都指向同一个函数,或者都表示相同的地址,它们比较相等。
  • 否则,指针比较不相等。

两个指针代表不同的完整对象的地址,都不为空,所以我们进入第三点,指针只是比较不相等。此处没有未定义或未指定的行为。

a == b应该刚好生成false

最新更新