Sunday, November 22, 2009

C++: what is difference between "new T" from "new T()"

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)

No comments:

Post a Comment