1108

If 'Test' is an ordinary class, is there any difference between:

Test* test = new Test;

and

Test* test = new Test();
Paul Maserrat
  • 3,411
  • 3
  • 22
  • 24
David Read
  • 11,031
  • 3
  • 17
  • 5
  • 2
    This is related to (but not identical to) http://stackoverflow.com/questions/1613341/what-do-the-following-phrases-mean-in-c-zero-default-and-value-initializati – Steve Jessop Dec 07 '10 at 17:21
  • 1
    Just use new Test() to make sure it is zero-initialized – Sung Jul 06 '16 at 05:51

8 Answers8

1029

Let's get pedantic, because there are differences that can actually affect your code's behavior. Much of the following is taken from comments made to an Old New Thing article

Sometimes the memory returned by the new operator will be initialized, and sometimes it won't depending on whether the type you're newing up is a POD (plain old data), or if it's a class that contains POD members and is using a compiler-generated default constructor.

  • In C++1998 there are 2 types of initialization: zero and default
  • In C++2003 a 3rd type of initialization, value initialization was added.

Assume:

struct A { int m; }; // POD
struct B { ~B(); int m; }; // non-POD, compiler generated default ctor
struct C { C() : m() {}; ~C(); int m; }; // non-POD, default-initialising m

In a C++98 compiler, the following should occur:

  • new A - indeterminate value

  • new A() - zero-initialize

  • new B - default construct (B::m is uninitialized)

  • new B() - default construct (B::m is uninitialized)

  • new C - default construct (C::m is zero-initialized)

  • new C() - default construct (C::m is zero-initialized)

In a C++03 conformant compiler, things should work like so:

  • new A - indeterminate value

  • new A() - value-initialize A, which is zero-initialization since it's a POD.

  • new B - default-initializes (leaves B::m uninitialized)

  • new B() - value-initializes B which zero-initializes all fields since its default ctor is compiler generated as opposed to user-defined.

  • new C - default-initializes C, which calls the default ctor.

  • new C() - value-initializes C, which calls the default ctor.

So in all versions of C++ there's a difference between new A and new A() because A is a POD.

And there's a difference in behavior between C++98 and C++03 for the case new B().

This is one of the dusty corners of C++ that can drive you crazy. When constructing an object, sometimes you want/need the parens, sometimes you absolutely cannot have them, and sometimes it doesn't matter.

TYeung
  • 2,579
  • 2
  • 15
  • 30
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • For `new C` and `new C()` under C++03, is `m` left uninitialised? What about for `struct D { D() : {} int m; }` (i.e. non-POD due to user-defined ctor, but m is not mentioned)? – j_random_hacker Dec 07 '10 at 17:00
  • Seems my `struct D` was mentioned later in that Old New Thing comment thread! For both `new D` and `new D()`, `m` is not initialised. – j_random_hacker Dec 07 '10 at 17:12
  • 4
    @j_random_hacker, `new A()` will default-initialize the object in C++98, like it does with `new B()`, `new B`, `new C()` and `new C`, but *not* with `new A`. That is, default initialization is always done in C++98 when either: 1) The class is a non-POD and the initializer is missing, or 2) The initializer is `()`. default-initialization zero-initializes the object if it's a POD, but calls the default constructor for non-PODs. – Johannes Schaub - litb Jan 02 '11 at 13:32
  • @litb: Thanks, what about the cases for `C` in C++03? Michael's answer just says "calls the default ctor", but I'm not 100% certain what that implies. – j_random_hacker Jan 02 '11 at 14:14
  • So, `new A` means best performance because most likely the compiler won't initialize it; while `new A()` is a little safer as you will not come across indeterminate values, is that correct? – Deqing Jul 11 '12 at 01:55
  • 139
    Can someone add what is the case in C++11 now? – legends2k Aug 21 '12 at 04:39
  • Seems like having a `struct A` that requires `new A()` would be bad style because you can't create it like that on the stack. Better to initialize with a constructor. Would that be a fair comment? – Jon Nov 19 '12 at 05:57
  • 10
    @Jon: With C++11 you can do this in stack too; `B obj{};` will make the object value-initialized (to 0s) as opposed to `B obj;` which will be default-initialized (garbage). – legends2k May 07 '13 at 14:03
  • @Jon: Added the case of C++11 now which takes care of default initializing objects on stack too. – legends2k May 07 '13 at 14:22
  • In terms of coding style though, would it be fair to say that it's better to write a constructor than relying on the client of your class/struct knowing that they need to value-initialize? – Jon May 09 '13 at 01:39
  • 1
    @Jon: Well, I'd say it depends. Not all classes are written for external consumption where the client is some Joe coder who wouldn't know; some classes are written for a library's internal consumption, in such cases I guess going with POD is better, but in cases where it's absolutely necessary to always initialize vars into a particular state (and perf. isn't a prob) then ctor seems to be better. – legends2k May 14 '13 at 11:14
  • Under which rule does the `= default` syntax apply to? i.e. if you had, `B() = default;`, that is a compiler generated constructor, so I'm assuming it would still leave `B::m` uninitialised when default-initialising? – Mark Ingram Feb 24 '14 at 09:17
  • I removed the "C++11 update" since it is not related to the topic of the question (`new T` vs. `new T()`) so was quite confusing. There *are* differences in C++11, where value initialized user defined types get members *zero* initialized if they are built-in types and not initialized in the default constructor initialization list. – juanchopanza Mar 14 '14 at 10:14
  • 1
    @MarkIngram AFAIK by doing = default; you are explicitly providing a constructor (even tho it is a compiler generated one, so you are in case B). If you don't provide a constructor, the compiler might implicitly generate it anyways (you remain in case A). The outcome is the same: new A/B -> default initialization, new A/B() -> value-initialization to zero. However, in C++11 you should not consider PODs but aggregates... – gnzlbg Mar 26 '14 at 14:41
  • Another interesting case to add would be `struct D { D() { }; ~D(); int m; };`, which has a user-defined constructor which doesn't explicitly initialize a POD member. – musiphil Sep 16 '14 at 23:42
  • `new A - indeterminate value. new A() - zero-initialize`. Can anyone explain this? What is meant by indeterminate value and what is meant by zero initialize? – SexyBeast Jan 11 '15 at 19:34
  • 7
    You say that "sometimes you absolutely cannot have them [parentheses]". What situation is it where you can't add them? – kec Apr 25 '15 at 17:07
  • ^ I have the same question. I don't believe it ever has harmful semantics to include the parentheses. – user541686 Jun 11 '15 at 19:11
  • 2
    @kec: maybe you want to avoid a call to the compiler generated default constructor, because that would call the default constructor for all members - which could have side-effects you might want to avoid (e.g. opening file descriptors or sockets when what you actually want is to reuse something that already exists instead). imo if you need to hack your code like that there's a flaw in your design, but then again in the real world you encounter stuff you can't or don't want to change often enough... – a.peganz Jul 20 '15 at 10:09
  • @CupidVogel: indeterminate value means the actual value depends on whatever the operating system and the implementation of the new operator have done with the chunk of memory you're getting. zero initialize means the chunk of memory is all zeroes. – a.peganz Jul 20 '15 at 10:15
  • @kec Search for 'most vexing parse'. – Chnossos Oct 03 '16 at 15:31
  • In C++11/14, iff. A is a class/struct/aggregate with a default ctor that is explicitly/implicitly defined as `=default;` and will not be implicitly deleted(`=delete;`), then there is a difference: `new A();` ensures all non-reference data members(subobjects) that are not initialized by default ctor are _0-initialized_, while `new A;` don't. – philsumuru Nov 24 '16 at 01:47
  • 13
    So the tl;dr is that `new A` gives members an indeterminate value and `new A()` initializes member values to 0... unless `A` has a destructor defined, in which case both expressions give members indeterminate values... unless `A` also has a constructor defined, in which case both expressions zero-initialize members... unless it's a C++03 compiler in which case `new A()` will "value initialize" the members instead, which is different somehow(?). So simple. – BlueRaja - Danny Pflughoeft Mar 06 '17 at 20:02
  • There is a 4th possibility: struct with user defined constructor, built in member and class member, it initialises the class member but NOT the built in member. What happens with new D versus new D() ? – SJHowe Sep 06 '19 at 09:05
  • @BlueRaja-DannyPflughoeft Good summary, it should be a good answer! ***unless A also has a constructor defined, in which case both expressions zero-initialize members...***, could you please explain that in more details. Maybe a simple example makes it clear enough. – John May 05 '22 at 03:06
  • @legends2k Time flies, 9 years later. I read your comment and a question raises. ***With C++11 you can do this in stack too; B obj{}; will make the object value-initialized (to 0s) as opposed to B obj; which will be default-initialized (garbage).*** It seems that there is no difference between them for this [code snippet](godbolt.org/z/7z3x4Krvb). Please pay attention to the outputs of the said code snippet. – John May 05 '22 at 04:09
  • @John I think the question you're alluding to is _Why doesn't `new B` vs `new B()` have any difference? Both seem to zero-initialize?_ As per [value-initialization documentation](http://en.cppreference.com/w/cpp/language/value_initialization), `if T is a class type with a default constructor that is neither user-provided nor deleted, the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor`. In your example, `B` is an aggregate, trivial, default-constructible, standard layout type. Hence it's just zero initialized in both cases. – legends2k May 07 '22 at 17:09
  • How about `new (A)`? – Thomas Weller Jul 05 '22 at 08:15
90

new Thing(); is explicit that you want a constructor called whereas new Thing; is taken to imply you don't mind if the constructor isn't called.

If used on a struct/class with a user-defined constructor, there is no difference. If called on a trivial struct/class (e.g. struct Thing { int i; };) then new Thing; is like malloc(sizeof(Thing)); whereas new Thing(); is like calloc(sizeof(Thing)); - it gets zero initialized.

The gotcha lies in-between:

struct Thingy {
  ~Thingy(); // No-longer a trivial class
  virtual WaxOn();
  int i;
};

The behavior of new Thingy; vs new Thingy(); in this case changed between C++98 and C++2003. See Michael Burr's explanation for how and why.

SebastianWilke
  • 470
  • 1
  • 4
  • 15
kfsone
  • 1,001
  • 7
  • 2
22

In general we have default-initialization in first case and value-initialization in second case.

For example: in case with int (POD type):

  • int* test = new int - we have any initialization and value of *test can be any.

  • int* test = new int() - *test will have 0 value.

next behaviour depended from your type Test. We have defferent cases: Test have defult constructor, Test have generated default constructor, Test contain POD member, non POD member...

hivert
  • 10,579
  • 3
  • 31
  • 56
bayda
  • 13,365
  • 8
  • 39
  • 48
18

No, they are the same. But there is a difference between:

Test t;      // create a Test called t

and

Test t();   // declare a function called t which returns a Test

This is because of the basic C++ (and C) rule: If something can possibly be a declaration, then it is a declaration.

Edit: Re the initialisation issues regarding POD and non-POD data, while I agree with everything that has been said, I would just like to point out that these issues only apply if the thing being new'd or otherwise constructed does not have a user-defined constructor. If there is such a constructor it will be used. For 99.99% of sensibly designed classes there will be such a constructor, and so the issues can be ignored.

  • 22
    Note that this is a particularly important point because the line "Test t(5);" is equivalent to "Test t = Test(5);" -- but "Test t();" is very different from "Test t = Test();". +1 – ojrac Mar 06 '09 at 20:03
  • 11
    -1, I disagree with your statement that the issues can be ignored. You don't have to know the rules precisely, but you should be aware of them in case you have to new a class without a user-defined default constructor (you should then either write the constructor or look up the rules). – avakar Mar 06 '10 at 07:02
  • 12
    -1 for a known incorrect answer. Your Edit ignores the presence of code written by former C programmers who didn't understand/use constructors. – Tom Apr 16 '10 at 11:00
  • 5
    What about classes like struct point { float v[3]; };? For things like that, a constructor would be a bad idea, as it would prevent all the nice properties that come with being POD and aggregate. So "the issues can be ignored" is just wrong, imo. – me22 Jan 02 '11 at 03:56
  • I suspect that > 0.001% of c++ code uses c code somewhere in it. – cheshirekow Jul 20 '12 at 21:29
  • This issue is now resolved with C++11's uniform initialization syntax. See the accepted answer. – legends2k May 07 '13 at 14:39
  • 6
    But they are not the same. This answer is plain wrong. It should be fixed or removed, because it seems to have caused some confusion, judging by the high number of up-votes. – juanchopanza Aug 11 '14 at 05:59
  • The statement "If something can possibly be a declaration, then it is a declaration." is true in itself, but it doesn't help here: an object definition (such as `Test t;`) is still a declaration, so both candidates (obj def? func decl?) are declarations and the statement cannot be used for disambiguation. – musiphil Sep 17 '14 at 16:44
  • In fact, the grammar allows `Test t();` to be parsed only as a function declaration, because `()` cannot be an _initializer_, which requires a non-empty _expression-list_. Therefore, there's no ambiguity to begin with. – musiphil Sep 17 '14 at 16:45
  • 1
    This answer is plain wrong. OP asked about new-ing up objects not the difference between declaration/definition and function declarations. – Tanveer Badar Jun 11 '19 at 10:10
10

Assuming that Test is a class with a defined constructor, there's no difference. The latter form makes it a little clearer that Test's constructor is running, but that's about it.

Evan Shaw
  • 23,839
  • 7
  • 70
  • 61
4

The rules for new are analogous to what happens when you initialize an object with automatic storage duration (although, because of vexing parse, the syntax can be slightly different).

If I say:

int my_int; // default-initialize → indeterminate (non-class type)

Then my_int has an indeterminate value, since it is a non-class type. Alternatively, I can value-initialize my_int (which, for non-class types, zero-initializes) like this:

int my_int{}; // value-initialize → zero-initialize (non-class type)

(Of course, I can't use () because that would be a function declaration, but int() works the same as int{} to construct a temporary.)

Whereas, for class types:

Thing my_thing; // default-initialize → default ctor (class type)
Thing my_thing{}; // value-initialize → default-initialize → default ctor (class type)

The default constructor is called to create a Thing, no exceptions.

So, the rules are more or less:

  • Is it a class type?
    • YES: The default constructor is called, regardless of whether it is value-initialized (with {}) or default-initialized (without {}). (There is some additional prior zeroing behavior with value-initialization, but the default constructor is always given the final say.)
    • NO: Were {} used?
      • YES: The object is value-initialized, which, for non-class types, more or less just zero-initializes.
      • NO: The object is default-initialized, which, for non-class types, leaves it with an indeterminate value (it effectively isn't initialized).

These rules translate precisely to new syntax, with the added rule that () can be substituted for {} because new is never parsed as a function declaration. So:

int* my_new_int = new int; // default-initialize → indeterminate (non-class type)
Thing* my_new_thing = new Thing; // default-initialize → default ctor (class type)
int* my_new_zeroed_int = new int(); // value-initialize → zero-initialize (non-class type)
     my_new_zeroed_int = new int{}; // ditto
       my_new_thing = new Thing(); // value-initialize → default-initialize → default ctor (class type)

(This answer incorporates conceptual changes in C++11 that the top answer currently does not; notably, a new scalar or POD instance that would end up an with indeterminate value is now technically now default-initialized (which, for POD types, technically calls a trivial default constructor). While this does not cause much practical change in behavior, it does simplify the rules somewhat.)

ThatsJustCheesy
  • 1,370
  • 14
  • 24
2

I wrote some sample codes below, as a supplement to the answer of Michael Burr:

#include <iostream>

struct A1 {
    int i;
    int j;
};

struct B {
    int k;
    B() : k(4) {}
    B(int k_) : k(k_) {}
};

struct A2 {
    int i;
    int j;
    B b;
};

struct A3 {
    int i;
    int j;
    B b;
    A3() : i(1), j(2), b(5) {}
    A3(int i_, int j_, B b_): i(i_), j(j_), b(b_) {}
};

int main() {
    {
        std::cout << "Case#1: POD without ()\n";
        A1 a1 = {1, 2};
        std::cout << a1.i << " " << a1.j << std::endl;
        A1* a = new (&a1) A1;
        std::cout << a->i << " " << a->j  << std::endl;
    }
    {
        std::cout << "Case#2: POD with ()\n";
        A1 a1 = {1, 2};
        std::cout << a1.i << " " << a1.j << std::endl;
        A1* a = new (&a1) A1();
        std::cout << a->i << " " << a->j  << std::endl;
    }
    {
        std::cout << "Case#3: non-POD without ()\n";
        A2 a1 = {1, 2, {3}};
        std::cout << a1.i << " " << a1.j << " " << a1.b.k << std::endl;
        A2* a = new (&a1) A2;
        std::cout << a->i << " " << a->j << " " << a->b.k << std::endl;
    }
    {
        std::cout << "Case#4: non-POD with ()\n";
        A2 a1 = {1, 2, {3}};
        std::cout << a1.i << " " << a1.j << " " << a1.b.k  << std::endl;
        A2* a = new (&a1) A2();
        std::cout << a->i << " " << a->j << " " << a1.b.k << std::endl;
    }
    {
        std::cout << "Case#5: user-defined-ctor class without ()\n";
        A3 a1 = {11, 22, {33}};
        std::cout << a1.i << " " << a1.j << " " << a1.b.k << std::endl;
        A3* a = new (&a1) A3;
        std::cout << a->i << " " << a->j << " " << a->b.k << std::endl;
    }
    {
        std::cout << "Case#6: user-defined-ctor class with ()\n";
        A3 a1 = {11, 22, {33}};
        std::cout << a1.i << " " << a1.j << " " << a1.b.k  << std::endl;
        A3* a = new (&a1) A3();
        std::cout << a->i << " " << a->j << " " << a1.b.k << std::endl;
    }
    return 0;
}

/*
output with GCC11.1(C++20)
Case#1: POD without ()
1 2
1 2
Case#2: POD with ()
1 2
0 0
Case#3: non-POD without ()
1 2 3
1 2 4
Case#4: non-POD with ()
1 2 3
0 0 4
Case#5: user-defined-ctor class without ()
11 22 33
1 2 5
Case#6: user-defined-ctor class with ()
11 22 33
1 2 5
*/
uqb
  • 300
  • 4
  • 7
0

According to n4713:

8.5.2.4/18:

A new-expression that creates an object of type T initializes that object as follows:

  • If the new-initializer is omitted, the object is default-initialized (11.6).
  • Otherwise, the new-initializer is interpreted according to the initialization rules of 11.6 for direct-initialization.

11.6/11:

An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized.

[Note: Since () is not permitted by the syntax for initializer,

X a();

is not the declaration of an object of class X, but the declaration of a function taking no argument and returning an X. The form () is permitted in certain other initialization contexts (8.5.2.4, 8.5.1.3, 15.6.2). - end note]

Also in 11.6/(17.4):

  • If the initializer is (), the object is value-initialized.

So the answer is that () will value-initialize that object, while the other one (without an explicit initializer) will default-initialize that object.

11.6/8:

To value-initialize an object of type T means:

  • if T is a (possibly cv-qualified) class type with either no default constructor or a default constructor that is user-provided or deleted, then the object is default-initialized;
  • If T is a (possibly cv-qualified) class type without a user-provided or deleted default constructor, then the object is zero-initialized and the semantic constraints for default-initialization are checked, and if T has a non-trivial default constructor, the object is default-initialized;
  • If T is an array type, the each element is value-initialized;
  • otherwise, the object is zero-initialized.

11.6/7:

To default-initialize an object of type T means:

  • If T is a (possibly cv-qualified) class type, constructors are considered. The applicable constructors are enumerated, and the best one for the initializer () is chosen through overload resolution. The constructor thus selected is called, with an empty argument list, to initialize the object.
  • If T is an array type, each element is default-initialized.
  • Otherwise, no initialization is performed.
GKxx
  • 93
  • 7