Recently I received an interesting question: what difference between "
new T
" from "
new T()
" in C++?
Let's look at example:
#include
#include
using namespace std;
class ST {
public:
ST() {
cout << "ST constructor executed" << endl;
}
};
class T {
public:
int i;
ST st;
};
int main() {
char mem[1000];
T *t_ptr;
memset(mem, 0x0F, sizeof(mem));
t_ptr = new(mem) T;
cout << "new T: " << int(t_ptr->i) << endl;
memset(mem, 0x0F, sizeof(mem));
t_ptr = new(mem) T();
cout << "new T(): " << int(t_ptr->i) << endl;
T t;
cout << "T t: " << int(t.i) << endl;
t = T();
cout << "t = T(): " << int(t.i) << endl;
return 0;
}
Output is:
ST constructor executed
new T: 252645135
ST constructor executed
new T(): 0
ST constructor executed
T t: 134515321
ST constructor executed
t = T(): 0
When we use
"new T"
and
"T t"
form, t-object default-initialized (in our example via default constructor). In C++ for backward compatibility with C default constructor initialize only non-POD class members. Therefore, called ST constructor and 'i' not initialized.
In case with
"new T()"
and
"t = T()"
we get value-initialized object. In our example each class member initialized separately.
For more information read this quotes from the
C++ standard (ANSI ISO IEC 14882 2003):
A new-expression that creates an object of type T initializes that object as follows:
- If the new-initializer is omitted:
- If T is a (possibly cv-qualified) non-POD class type (or array thereof), the object is default-initialized (8.5). If T is a const-qualified type, the underlying class type shall have a user-declared default constructor.
- Otherwise, the object created has indeterminate value. If T is a const-qualified type, or a (possibly cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of const-qualified type, the program is ill-formed;
- If the new-initializer is of the form (), the item is value-initialized (8.5);
- If the new-initializer is of the form (expression-list) and T is a class type, the appropriate constructor is called, using expression-list as the arguments (8.5);
- If the new-initializer is of the form (expression-list) and T is an arithmetic, enumeration, pointer, or pointer-to-member type and expression-list comprises exactly one expression, then the object is initialized to the (possibly converted) value of the expression (8.5);
- Otherwise the new-expression is ill-formed.
(5.4.3. New, page 82)
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 member89) 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.
An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.
(8.5. Initializers, page 145)