C++ new A 和 new A() 的區別詳解

發表於2016-12-26

我們在C++程式中經常看到兩種new的使用方式:new A以及new A()。那麼這兩種究竟有什麼區別呢?

呼叫new分配的記憶體有時候會被初始化,而有時候不會,這依賴於A的型別是否是POD(Plain old data)型別,或者它是否是包含POD成員、使用編譯器生成預設建構函式的類。

附:POD型別

POD是Plain old data的縮寫,它是一個struct或者類,且不包含建構函式、解構函式以及虛擬函式。

維基百科給出了更加詳細的解釋:

C++的POD型別或者是一個標量值,或者是一個POD型別的類。POD class沒有使用者定義的解構函式、拷貝建構函式和非靜態的非POD型別的資料成員。而且,POD class必須是一個aggregate,沒有使用者定義的建構函式,沒有私有的或者保護的非靜態資料,沒有基類或虛擬函式。它只是一些欄位值的集合,沒有使用任何封裝以及多型特性。

附:aggregate的定義:

An aggregate is an array or a class (clause 9) with no user-declared constructors (12.1), no private or protected non-static data members (clause 11), no base classes (clause 10), and no virtual functions (10.3).

接著介紹一下C++中的三種初始化方式:

zero-initialization,default-initialization,value-initialization。

首先需要注意的是value-initialization是在C++2003標準中新引入的,在原來的1998標準中並不存在。

C++03標準中針對這三種方式的說明:

To zero-initialize an object of type T means:

— if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
— if T is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;
— if T is a union type, the object’s first named data member is zero-initialized;
— if T is an array type, each element is zero-initialized;
— if T is a reference type, no initialization is performed.

To default-initialize an object of type T means:

— if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is an array type, each element is default-initialized;
— otherwise, the object is zero-initialized.

To value-initialize an object of type T means:

— if T is a class type (clause 9) with a user-declared constructor (12.1), then the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
— if T is a non-union class type without a user-declared constructor, then every non-static data member and base-class component of T is value-initialized;
— if T is an array type, then each element is value-initialized;
— otherwise, the object is zero-initialized

A program that calls for default-initialization or value-initialization of an entity of reference type is ill-formed. If T is a cv-qualified type, the cv-unqualified version of T is used for these definitions of zero-initialization, default-initialization, and value-initialization.

注意:VS2008遵循的是98標準,而GCC3.4.5遵循的是03標準。

採用如下程式碼可以驗證編譯器遵循的到底是哪一種標準:

在VS008中輸出就不是0,說明遵循的是98標準。

下面先看一段C++示例程式碼:

執行結果:

上述測試平臺是VS2008.需要注意的是,VS08只支援C++98。

在這種情況下:

new A:不確定的值

new A():zero-initialize

new B:預設構造(B::m未被初始化)

new B():預設構造(B::m未被初始化)

new C:預設構造(C::m被zero-initialize)

new C():預設構造(C::m被zero-initialize)

如果用相容C++03的編譯器,比如G++結果:

new A:不確定的值

new A():value-initialize A,由於是POD型別所以是zero initialization

new B:預設構造(B::m未被初始化)

new B():value-initialize B,zero-initialize所有欄位,因為使用的預設建構函式

new C:default-initialize C,呼叫預設建構函式

new C():value-initialize C,呼叫預設建構函式

在所有C++版本中,只有當A是POD型別的時候,new A和new A()才會有區別。而且,C++98和C++03會有區別。

參考資料:

What are POD types in C++?

What are Aggregates and PODs and how/why are they special?

相關文章