新的int[10]()是合法的C++吗?

26

在尝试回答这个问题时,我发现代码int* p = new int[10]();可以在VC9编译器中正常编译并将整数初始化为0。因此,我的问题如下:

  1. 首先,这是否是有效的C++代码还是微软的扩展?
  2. 它是否保证初始化数组的所有元素?
  3. 另外,如果我使用new int;new int();,是否有任何区别?后者是否保证初始化变量?
4个回答

29

首先,这是有效的C++代码还是微软扩展?

这是有效的C++代码,相关的标准部分是5.3.4,第一段包含了语法规则。

它能保证初始化数组的所有元素吗?

可以。第5.3.4/15段陈述:

创建类型为T的对象的new-expression会按如下方式初始化该对象:

...

  • 如果new-initializer的形式为(),则该项进行值初始化(8.5)

其中,对于POD类型的值初始化意味着零初始化。

此外,如果我使用new int;和new int();有什么区别?后者是否保证初始化变量?

它们是不同的。根据上面的引用,new int()将会零初始化整数。在同一段落的前一个块中:

如果省略了new-initializer:

  • 如果T是(可能带有cv限定符的)非POD类类型(或其数组),则该对象进行默认初始化(8.5)。如果T是const限定类型,则基础类类型必须具有用户声明的默认构造函数。

  • 否则,创建的对象具有未确定的值。如果T是const限定类型,或(可能带有cv限定符的)包含(直接或间接地)const限定类型成员的POD类类型(或其数组),则程序是非法的;

因此,new int将不会初始化内存。


2
从标准来看,“对于类型T进行默认初始化的意思是:如果T是非POD类类型[例如vector],则会调用T的默认构造函数。”
构造符号“T()”用于表示类型T的默认值,并且对于内置类型而言,这个值为零;对于用户定义的类型,则使用默认构造函数。构造符号“POD()”产生值初始化,根据标准,这将导致所有成员和子成员被默认构造或者被零初始化。
这就是为什么你的声明是合法的原因,但是它是否按照标准进行了零初始化需要进行详细查找(个人认为)。
但是,我无法在标准中找到有关内置类型默认构造的含义的定义。
struct S { int x; };

void f () {
   S s1;       // s1.x is uninitialized here
   S s2 = S(); // s2.x is zero here
}

我认为我们经常对内置类型的默认构造函数进行自己的解释;因为C++标准没有定义它(至少我找不到),我记得Stroustrup或Josuttis说它意味着T(),被描述为值初始化时是内置类型的"0转换为T类型"。

由于int*是一种内置类型,所以它被初始化为零。

但我真的不确定。


1
那真的是初始化列表吗?我以为那些是 {1,2,3}? - Macke
在编辑方面:标准为所有初始化规则提供了完整的定义,即使它们相当复杂且难以遵循。 §8.5/9指出,如果未为非静态POD对象指定初始化程序,则其将具有不确定的初始值(我认为这就是您所称的“默认构造”,与默认初始化不同)。 §8.5/7指出,空括号作为初始化程序意味着值初始化 - David Rodríguez - dribeas
@dribeas:好的。所以§8.5/6应该写成“默认值初始化”而不是“默认构造”。我是对的吗?顺便说一句,草案的n3000版本似乎已经纠正了这个问题。 - Abhay
@Abhay:§8.5/6 写道:“在任何其他初始化发生之前,所有静态存储期对象都必须在程序启动时进行零初始化。”这里没有“默认值初始化”的概念。您查看的标准版本是哪个?(引用来自 INCITS ISO IEC 14882:2003,这是当前的标准) - David Rodríguez - dribeas
@David,啊,那样就有意义了。我确实喜欢C++0x在“new”中使用的新方法,但我同样不喜欢它不能从列表中推导出参数数量的方式。new int[]{1, 2}是不起作用的。人们必须说new int[2]{1, 2},我认为这很糟糕。 - Johannes Schaub - litb
显示剩余5条评论

1
  1. 这是根据第5.3.4/1段有效的C++代码,由于特殊格式很难在此引用。

  2. 根据第5.3.4/15条款,如果使用form(),则该项将进行值初始化,请参见第8.5段,但简短的答案是是。

  3. 是的,在第一种情况下,变量未进行值初始化,可以是任何值,在第二种情况下,它进行了值初始化,并且将为零。


0

如果我可以猜测一下(如果我错了,我相信会被纠正):

后者()进行值初始化(在标准中称为值初始化),这使得整数在这种情况下具有值0。

这是标准的一个相当新的补充(C++03?),因此旧编译器可能不支持它,并且将其保留为未初始化状态。

我记得在从MSVS 2003切换到2005(我想是那个版本)时,我收到了很多关于这个的警告,其中编译器说“现在将对该成员进行零初始化,以前没有进行过”。


没有所谓的C++03标准,尽管MSVS每个版本都变得更加符合标准。 - Gorpik
3
@Gorpik,当前的标准是ISO/IEC 14882:2003。如果你按照命名标准的常规方法将其命名为年份,那么它应该被称为c++03,尽管这不是正确的名称(即使大多数人会这样称呼,下一个标准肯定不会被称为c++11)。 - David Rodríguez - dribeas
抱歉,你是对的。我忘记了2003年发布的标准修正案。 - Gorpik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接