Do the parentheses after the type name make a difference with new?
Asked Answered
H

8

1115

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

Test* test = new Test;

and

Test* test = new Test();
Heliochrome answered 6/3, 2009 at 19:39 Comment(2)
This is related to (but not identical to) stackoverflow.com/questions/1613341/…Stole
Just use new Test() to make sure it is zero-initializedBeckman
R
1035

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.

Revue answered 6/3, 2009 at 21:1 Comment(32)
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)?Discontinue
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.Discontinue
@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.Townsley
@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.Discontinue
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?Poetize
Can someone add what is the case in C++11 now?Carsoncarstensz
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?Ghastly
@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).Carsoncarstensz
@Jon: Added the case of C++11 now which takes care of default initializing objects on stack too.Carsoncarstensz
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?Ghastly
@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.Carsoncarstensz
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?Kirkham
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.Echevarria
@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...Abmho
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.Shurwood
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?Clarance
You say that "sometimes you absolutely cannot have them [parentheses]". What situation is it where you can't add them?Gaslight
^ I have the same question. I don't believe it ever has harmful semantics to include the parentheses.Resupinate
@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...Willard
@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.Willard
@Gaslight Search for 'most vexing parse'.Chasten
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.Euripus
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.Throstle
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() ?Sheathbill
@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.Grits
@Carsoncarstensz 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.Grits
@Grits 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, 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.Carsoncarstensz
How about new (A)?Pyrotechnic
@Carsoncarstensz That is wrong. Accroding to cppreference, the default constructor will be called, which doesn't give garbage values.Marianelamariani
@Marianelamariani Well, can you be more specific? Your comment is vague and lacks specificity. Default constructors doesn't do any initialization and hence leave members in indeterminate state (garbage); this can be seen in John's example too. However, when you have the statement new B the value-initialization behaviour in my above comment kicks-in and then the implicitly-provided default constructor provided zeros out the members.Carsoncarstensz
@Carsoncarstensz My comment was wrong, but your reply seems incorrect, too. Why would new B be value-initialized? It should be default-initialized since there are no parentheses after B, so the member m would also be default-initialized and have an indeterminate value.Marianelamariani
new B seems strange to me too. It should be default initialized (and be left as garbage) but it doesn't seem to be. Adding the statement new B seems to give a n implicit default constructor that zero initializes while dropping it returns the expected behaviour of garbage. This is in GCC with C++17 config.Carsoncarstensz
C
92

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.

Cactus answered 15/2, 2013 at 19:57 Comment(0)
L
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 don't have any initialization and the value of *test can be anything.

  • 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...

Libelous answered 6/3, 2009 at 20:0 Comment(0)
C
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.

Caryophyllaceous answered 6/3, 2009 at 19:42 Comment(10)
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();". +1Anarch
-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).Easting
-1 for a known incorrect answer. Your Edit ignores the presence of code written by former C programmers who didn't understand/use constructors.Molli
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.Kelle
I suspect that > 0.001% of c++ code uses c code somewhere in it.Irreconcilable
This issue is now resolved with C++11's uniform initialization syntax. See the accepted answer.Carsoncarstensz
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.Echevarria
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.Shurwood
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.Shurwood
This answer is plain wrong. OP asked about new-ing up objects not the difference between declaration/definition and function declarations.Nazarene
T
11

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.

Torray answered 6/3, 2009 at 19:42 Comment(0)
D
5

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.)

Denning answered 20/8, 2020 at 4:47 Comment(0)
B
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
*/
Benevolent answered 1/9, 2021 at 9:16 Comment(0)
O
1

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.
Oceanid answered 24/3, 2023 at 9:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.