Fed*_*dor 13 c++ constructor new-operator language-lawyer
我有一个 C++ 概念来检查对象数组是否可以动态分配:
template< class T, int N >
concept heap_constructible = requires() {
delete[] new T[N];
};
Run Code Online (Sandbox Code Playgroud)
我意外地发现,在零大小数组N=0
和不可访问的(例如private:
)构造函数的情况下,编译器的评估会出现分歧:
class A {
A();
};
static_assert( !heap_constructible<A, 5> ); // OK everywhere
static_assert( heap_constructible<A, 0> ); // OK in GCC only
Run Code Online (Sandbox Code Playgroud)
只有 GCC 似乎允许零大小分配A
-objects。Clang 打印错误:
calling a private constructor of class 'A'
Run Code Online (Sandbox Code Playgroud)
如果概念稍作修改:
template< class T, int N >
concept heap_constructible1 = requires() {
delete[] new T[N]{}; // note additional empty braced list
};
Run Code Online (Sandbox Code Playgroud)
Clang 也接受它:
static_assert( heap_constructible1<A, 0> ); // OK in GCC and Clang
Run Code Online (Sandbox Code Playgroud)
但不是 MSVC,它同时评估heap_constructible<A, 0>
和。在线演示:https://gcc.godbolt.org/z/nYr88avM4heap_constructible1<A, 0>
false
这里是哪个编译器?
目前尚未明确new 表达式对构造函数的使用;这是CWG2102(源自此Clang 问题)。
new 表达式中绑定的数组不必是常量表达式,如果不是常量表达式,则在运行时之前无法判断new 初始化程序是否覆盖了数组的每个元素,或者是否需要进行额外的初始化对于尾随元素。这意味着,一般来说,元素类型需要是可默认构造的。
然而,当数组界限是常量表达式时,这个要求就显得多余了。事实上,所有主要实现都接受#1
如下例所示的代码(同时拒绝#2
):
struct S {
S() = delete;
S(int);
};
const int a = 3;
S* p = new S[a] {1, 2, 3}; // #1
int b = 3;
S* q = new S[b] {1, 2, 3}; // #2
Run Code Online (Sandbox Code Playgroud)
但该标准并没有区分这两种情况。
考虑到这一点,我想说 GCC 的行为在这里是最一致的:既不是默认值([dcl.init.general]/7.2),也不是聚合([dcl.init.aggr])零大小数组的初始化使用T
任何 的T
构造函数,因此如果new S[3] {1, 2, 3}
在上面的示例中没问题,new S[0]
也应该没问题。
归档时间: |
|
查看次数: |
352 次 |
最近记录: |