隐式对象创建是否适用于常量表达式?
Does implicit object creation apply in constant expressions?
#include <memory>
int main() {
constexpr auto v = [] {
std::allocator<char> a;
auto x = a.allocate(10);
x[2] = 1;
auto r = x[2];
a.deallocate(x, 10);
return r;
}();
return v;
}
程序格式错误吗? Clang 这么认为,GCC 和 MSVC 不这么认为:https://godbolt.org/z/o3bcbxKWz
删除 constexpr
我认为该程序没有错误格式并且具有明确定义的行为:
通过 [allocator.members]/5 调用 a.allocate(10)
开始了它为其分配存储的 char[10]
数组的生命周期。
根据 [intro.object]/13 开始类型数组的生命周期 char
在其存储中隐式创建对象。
char
等标量类型是隐式生存期类型。 ([basic.types.general]/9
[intro.object]/10 然后说 char
类型的对象是在 char[10]
数组的存储中创建的(并且它们的生命周期开始)如果这可以给程序定义的行为。
如果 char
对象的生命周期不在 x[2]
开始,没有 constexpr
的程序将由于在其生命周期之外写入 x[2]
而出现未定义的行为,但是由于上述参数,可以隐式创建 char
对象,从而使程序行为明确定义为以状态 1
.
退出
对于constexpr
,我想知道程序是否格式错误。隐式对象创建是否适用于常量表达式?
根据 [intro.object]/10 隐式创建对象以赋予程序 定义的行为,但格式错误是否算作定义的行为?
如果不是,则程序不应该是格式错误的,因为为 x[2]
.
隐式创建了 char
对象
如果是,那么下一个问题是是否未指定程序是否格式错误,因为[intro.object]/10也说如果多个集合可以给出,则隐式创建哪些对象是未指定的程序定义的行为。
从语言设计的角度来看,我希望隐式对象创建不应该发生在常量表达式中,因为验证一组使常量表达式有效的对象的(不)存在对于编译器来说可能是不可行的一般。
这里的 Clang 是不正确的。您已经引用了规范中使其格式良好的所有部分。 std::allocator<T>::allocate
是 constexpr
;你得到一个指向 char*
的指针; allocator<T>::allocate
创建一个 T
的数组;创建 char
的数组隐式创建对象;访问 char
尝试导致 UB,但 IOC 阻止 UB,因此 UB 不会发生。因此:代码不允许格式错误。
Clang 声称完全支持 IOC 和 constexpr 分配器,所以这段代码应该可以工作。
Does implicit object creation apply in constant expressions?
所有表达式都是核心常量表达式unless [expr.const]/5 explicitly excludes it。那里没有提到可能是确定创建哪些对象的 UB 的操作,因此必须包括此类操作。
IOC 防止 表达式成为 UB。
I would expect that implicit object creation is not supposed to happen in constant expressions, because verifying the (non-)existence of a set of objects making the constant expression valid is probably infeasible for a compiler in general.
您忘记了对 constexpr 代码的其他限制。只要 [expr.const]/5 继续明确禁止 reinterpret_cast
和来自 void*
的转换,滥用 IOC 的方式就非常有限。例如,您不能将 allocate(10)
调用返回的指针转换为 int*
。所以编译器知道 唯一可以在该存储中隐式创建的对象 是 char
s.
所以在不断的评估时间,编译器可以只获取 allocator<char>::allocate
的结果并在返回它之前立即创建该数组的所有 char
成员。没有任何 constexpr 有效的方法可以获取该存储并隐式创建任何 other 而不是 char
s.
并且在 T
不是字节类型时使用 allocator<T>::allocate
将不会在该存储中隐式创建对象。所以要么你只是得到一个指向未成形元素数组的指针,要么你得到一个指向字节类型数组的指针。
我猜 Clang 忘了检查这个特殊情况。
2469. Implicit object creation vs constant expressions
It is not intended that implicit object creation, as described in 6.7.2 [intro.object] paragraph 10, should occur during constant expression evaluation, but there is currently no wording prohibiting it.
#include <memory>
int main() {
constexpr auto v = [] {
std::allocator<char> a;
auto x = a.allocate(10);
x[2] = 1;
auto r = x[2];
a.deallocate(x, 10);
return r;
}();
return v;
}
程序格式错误吗? Clang 这么认为,GCC 和 MSVC 不这么认为:https://godbolt.org/z/o3bcbxKWz
删除 constexpr
我认为该程序没有错误格式并且具有明确定义的行为:
通过 [allocator.members]/5 调用 a.allocate(10)
开始了它为其分配存储的 char[10]
数组的生命周期。
根据 [intro.object]/13 开始类型数组的生命周期 char
在其存储中隐式创建对象。
char
等标量类型是隐式生存期类型。 ([basic.types.general]/9
[intro.object]/10 然后说 char
类型的对象是在 char[10]
数组的存储中创建的(并且它们的生命周期开始)如果这可以给程序定义的行为。
如果 char
对象的生命周期不在 x[2]
开始,没有 constexpr
的程序将由于在其生命周期之外写入 x[2]
而出现未定义的行为,但是由于上述参数,可以隐式创建 char
对象,从而使程序行为明确定义为以状态 1
.
对于constexpr
,我想知道程序是否格式错误。隐式对象创建是否适用于常量表达式?
根据 [intro.object]/10 隐式创建对象以赋予程序 定义的行为,但格式错误是否算作定义的行为?
如果不是,则程序不应该是格式错误的,因为为 x[2]
.
char
对象
如果是,那么下一个问题是是否未指定程序是否格式错误,因为[intro.object]/10也说如果多个集合可以给出,则隐式创建哪些对象是未指定的程序定义的行为。
从语言设计的角度来看,我希望隐式对象创建不应该发生在常量表达式中,因为验证一组使常量表达式有效的对象的(不)存在对于编译器来说可能是不可行的一般。
这里的 Clang 是不正确的。您已经引用了规范中使其格式良好的所有部分。 std::allocator<T>::allocate
是 constexpr
;你得到一个指向 char*
的指针; allocator<T>::allocate
创建一个 T
的数组;创建 char
的数组隐式创建对象;访问 char
尝试导致 UB,但 IOC 阻止 UB,因此 UB 不会发生。因此:代码不允许格式错误。
Clang 声称完全支持 IOC 和 constexpr 分配器,所以这段代码应该可以工作。
Does implicit object creation apply in constant expressions?
所有表达式都是核心常量表达式unless [expr.const]/5 explicitly excludes it。那里没有提到可能是确定创建哪些对象的 UB 的操作,因此必须包括此类操作。
IOC 防止 表达式成为 UB。
I would expect that implicit object creation is not supposed to happen in constant expressions, because verifying the (non-)existence of a set of objects making the constant expression valid is probably infeasible for a compiler in general.
您忘记了对 constexpr 代码的其他限制。只要 [expr.const]/5 继续明确禁止 reinterpret_cast
和来自 void*
的转换,滥用 IOC 的方式就非常有限。例如,您不能将 allocate(10)
调用返回的指针转换为 int*
。所以编译器知道 唯一可以在该存储中隐式创建的对象 是 char
s.
所以在不断的评估时间,编译器可以只获取 allocator<char>::allocate
的结果并在返回它之前立即创建该数组的所有 char
成员。没有任何 constexpr 有效的方法可以获取该存储并隐式创建任何 other 而不是 char
s.
并且在 T
不是字节类型时使用 allocator<T>::allocate
将不会在该存储中隐式创建对象。所以要么你只是得到一个指向未成形元素数组的指针,要么你得到一个指向字节类型数组的指针。
我猜 Clang 忘了检查这个特殊情况。
2469. Implicit object creation vs constant expressions
It is not intended that implicit object creation, as described in 6.7.2 [intro.object] paragraph 10, should occur during constant expression evaluation, but there is currently no wording prohibiting it.