If 'Test' is an ordinary class, is there any difference between:
Test* test = new Test;
and
Test* test = new Test();
If 'Test' is an ordinary class, is there any difference between:
Test* test = new Test;
and
Test* test = new Test();
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.
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.
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 struct D
was mentioned later in that Old New Thing comment thread! For both new D
and new D()
, m
is not initialised. –
Discontinue 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 C
in C++03? Michael's answer just says "calls the default ctor", but I'm not 100% certain what that implies. –
Discontinue 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 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 B obj{};
will make the object value-initialized (to 0s) as opposed to B obj;
which will be default-initialized (garbage). –
Carsoncarstensz = 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 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 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 =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 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 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 new (A)
? –
Pyrotechnic 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 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 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.
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...
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.
Test t;
) is still a declaration, so both candidates (obj def? func decl?) are declarations and the statement cannot be used for disambiguation. –
Shurwood 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 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.
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:
{}
) or default-initialized (without {}
). (There is some additional prior zeroing behavior with value-initialization, but the default constructor is always given the final say.){}
used?
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.)
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
*/
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 anX
. 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 ifT
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.
© 2022 - 2024 — McMap. All rights reserved.