cig*_*ien 5 c++ new-operator language-lawyer c++20
对于以下程序:
int main()
{
new char[4] {"text"}; // #1
new char[5] {"text"}; // #2
new char[] {"text"}; // #3
}
Run Code Online (Sandbox Code Playgroud)
clang 给出了一个错误,#1
其中说:
error: initializer-string for char array is too long
Run Code Online (Sandbox Code Playgroud)
并接受#2
和#3
。
gcc 为所有语句给出以下错误:
error: invalid conversion from 'const char*' to 'char' [-fpermissive]
Run Code Online (Sandbox Code Playgroud)
此外,#3
它给出了错误:
error: expected primary-expression before ']' token
Run Code Online (Sandbox Code Playgroud)
那么该语言对这段代码是否格式良好有什么看法呢?
我想知道当前的规则,但我也很想知道这是否在该语言的先前版本中发生了变化。
Nic*_*las 11
好的,这很容易追踪。的存在{}
意味着正在执行列表初始化,因此我们可以访问规范中我们最喜欢的部分:[dcl.init.list]/3。
在情况 1 中被初始化的对象是 a char[4]
。花括号初始化器列表不是指定的初始化器,因此 3.1 被忽略。char[4]
不是一个类,所以 3.2 被忽略。这将我们带到 3.3:
否则,如果
T
是一个字符数组,并且初始化器列表有一个元素是适当类型的字符串文字 ([dcl.init.string]),则按照该子条款中的描述执行初始化。
嗯,char[4]
肯定是字符数组,并且初始化列表肯定包含单个元素,并且该元素实际上与字符数组的类型匹配。所以我们去[dcl.init.string]。
这告诉我们(在时尚之后):
string-literal 值的连续字符初始化数组的元素。
但下一段警告:
初始化器的数量不应多于数组元素。
好吧,这使得 #1 格式错误。
因此,我们重做char[5]
. 这不会触发,因为 5 足够大。
最后,我们来到char[]
. 就初始化而言,这与使用数字没有什么不同。char[]
是一个字符数组,所以它遵循上述规则。C++17 会因为char[]
在new
表达式中使用而窒息,但C++20 可以很好地使用它。
如果 type-id 或 new-type-id 表示未知边界的数组类型([dcl.array]),则不应省略 new-initializer;分配的对象是一个包含 n 个元素的数组,其中 n 由 new-initializer ([dcl.init.aggr], [dcl.init.string]) 中提供的初始元素的数量确定。
这意味着#2 和#3 应该是合法的。所以 GCC 使它们格式错误是错误的。由于错误的原因,它使 #1 格式错误。