C++ 比较C+中允许的动态分配对象的地址+;20常数表达式?

C++ 比较C+中允许的动态分配对象的地址+;20常数表达式?,c++,language-lawyer,constexpr,c++20,C++,Language Lawyer,Constexpr,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; }

只要内存不泄漏,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错误(或者尚未完全实现)。有人能证实这个假设吗?还是我错了

活生生的例子

编辑:奇怪的是,当我通过提供的链接打开live示例时,它突然也在gcc上编译。但如果我将其复制粘贴到新的编译器资源管理器实例,它将再次失败。或者,如果我多次重新加载它,它会每秒失败一次,每隔一秒编译一次…

这是一个gcc错误()

其中没有任何内容会导致对
a==b
的求值不能成为常量表达式。唯一有问题的是关于未定义行为的问题。我们可以看看指针比较的结果:

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

  • 如果一个指针表示一个完整对象的地址,另一个指针表示超过另一个完整对象最后一个元素的地址,则比较的结果是未指定的
  • 否则,如果指针都为null,都指向同一函数,或者都表示同一地址,则它们比较相等
  • 否则,指针比较不相等
两个指针都表示不同完整对象的地址,都不为null,因此我们进入第三个要点,指针只是比较不相等。这里没有未定义或未指定的行为


a==b
应该只产生
false

就可以确认gcc.godbolt的行为了。如果我仅用一个GCC窗口替换“一致性查看器”,它会100%显示正确的错误。@HolyBlackCat感谢您的确认。因此,至少这个错误不是godbolt的产物。那么每个新表达式都可以抛出的bad_alloc呢?@PiotrNycz这与在两个分配成功后比较指针有什么关系?我的意思是gcc可以证明可能的bad alloc是拒绝任何具有新表达式的constexpr程序的理由。诊断文本是一个QOI问题。;)