NoS*_*tAl 7 c++ constexpr c++20
在阅读有关 C++20 中 constexpr 新支持的 C++ Weekly视频的评论时,我发现该评论声称 C++20 允许在 constexpr 上下文中使用 UB。
起初我相信评论是正确的,但我越想越多,我开始怀疑 C++20 的措辞包含一些聪明的语言来实现这种定义的行为。
要么所有的临时分配都返回唯一的地址,或者可能是 C++ 中的一些更一般的概念,这使得 2 个不同的分配指针总是(即使在 nonconstexpr 上下文中)比较假,即使在实际运行时分配器可能会给你相同的地址(因为您删除了第一个分配)。
作为奖励的奇怪之处:您只能==用于比较<,>失败...
这是在 constexpr 中涉嫌 UB 的程序:
#include <iostream>
static constexpr bool f()
{
auto p = new int(1);
delete p;
auto q = new int(2);
delete q;
return p == q;
}
int main()
{
constexpr bool res1 = f();
std::cout << res1 << std::endl; // May output 0 or 1
}
Run Code Online (Sandbox Code Playgroud)
这里的结果是实现定义的。res1可能是假的、真的或格式错误的,具体取决于实现如何定义它。对于相等比较和关系比较来说都是如此。
[expr.eq](用于相等)和[expr.rel] (用于关系)都首先对指针进行左值到右值的转换(因为我们必须实际读取值来进行比较)。[conv.lval]/3表示转换的结果是:
否则,如果泛左值引用的对象包含无效的指针值([basic.stc.dynamic.deallocation]、[basic.stc.dynamic.safety]),则行为是实现定义的。
这里的情况就是这样:两个指针都包含无效的指针值,根据[basic.stc.general]/4:
当到达存储区域的持续时间结束时,表示该存储区域的任何部分的地址的所有指针的值变成无效指针值。通过无效指针值进行间接寻址以及将无效指针值传递给释放函数具有未定义的行为。对无效指针值的任何其他使用都具有实现定义的行为。
脚注如下:
某些实现可能定义复制无效的指针值会导致系统生成的运行时错误。
因此,我们从左值到右值转换中获得的值是......实现定义的。它可以以某种方式实现定义,使这两个指针比较相等。它可能是实现定义的,导致这两个指针比较不相等(显然所有实现都是如此)。或者它甚至可能是实现定义的,导致这两个指针之间的比较成为未指定或未定义的行为。
值得注意的是,[expr.const]/5(管理常量表达式的主要规则),尽管拒绝未定义的行为并显式拒绝任何结果未指定的比较([expr.const]/5.23),但对结果为实现的比较只字未提-定义。
这里没有未定义的行为。什么都可以。诚然,在不断的评估过程中这非常奇怪,我们希望看到一套更严格的规则。
值得注意的是,对于p < q,gcc 和 clang 似乎拒绝比较,因为它不是常量表达式(这是...允许的结果),而 msvc 认为 和p < q都是p > q常量表达式,其值为false(这是...也是允许的)结果)。
| 归档时间: |
|
| 查看次数: |
117 次 |
| 最近记录: |