C++ 比较C+中允许的动态分配对象的地址+;20常数表达式?
只要内存不泄漏,C++20允许在constexpr函数中进行堆分配。然而,GCC和Clang对于比较两个动态分配对象的地址是否是一个常量表达式存在分歧 以下代码段可以用Clang编译,但不能用gcc编译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; }
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,都指向同一函数,或者都表示同一地址,则它们比较相等
- 否则,指针比较不相等
a==b
应该只产生false
就可以确认gcc.godbolt的行为了。如果我仅用一个GCC窗口替换“一致性查看器”,它会100%显示正确的错误。@HolyBlackCat感谢您的确认。因此,至少这个错误不是godbolt的产物。那么每个新表达式都可以抛出的bad_alloc呢?@PiotrNycz这与在两个分配成功后比较指针有什么关系?我的意思是gcc可以证明可能的bad alloc是拒绝任何具有新表达式的constexpr程序的理由。诊断文本是一个QOI问题。;)