new X vs new X()

V

Victor Bazarov

Razvan said:
Is there any difference between new X and new X() ?!

There used to be, but only if X is a POD. The first form would
leave it uninitialised, the second would default-initialise it.

Nowadays I am not sure.

V
 
A

Andrew Koenig

Is there any difference between new X and new X() ?!

Yes, but it is very rare that you should care.

If you say "new X", the initial value of the object allocated is the same as
an uninitialized local variable of the same type would have. So, for
example, the result of "new int" is the address of an uninitialized int, and
the result of "new std::string" is the address of a std::string object with
no characters (because all strings are initialized, if only by the default
constructor). In contrast, the result of "new int()" is the address of an
int with value 0, and the result of "new std::string()" is exactly the same
as the result of "new std::string" (because all strings are initialized, if
only by the default constructor).

This is a relatively recent feature, so if you write a program that relies
on it, you may wish to make sure that your compiler implements it correctly.
 
R

Rob Williscroft

Victor Bazarov wrote in in comp.lang.c++:
There used to be, but only if X is a POD. The first form would
leave it uninitialised, the second would default-initialise it.

Nowadays I am not sure.


Nowadays its value-initialized, which is a kind-of recursive
default-intialization.

In 8.5/5

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;

8.5/7

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

Rob.
 
V

Victor Bazarov

Rob said:
Victor Bazarov wrote in in comp.lang.c++:





Nowadays its value-initialized, which is a kind-of recursive
default-intialization.

In 8.5/5

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;

8.5/7

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

Thanks, Rob. So, in the case of 'new X', if X is a POD it is still
_uninitialised_. The only difference now is that it's not "default-
initialised" for PODs but "value-initialised", right?

You don't have to reply, I'm just repeating here what Andrew Koenig's
reply stated (I hope).

Victor
 
R

Rob Williscroft

Victor Bazarov wrote in in comp.lang.c++:
Thanks, Rob. So, in the case of 'new X', if X is a POD it is still
_uninitialised_. The only difference now is that it's not "default-
initialised" for PODs but "value-initialised", right?

You don't have to reply, I'm just repeating here what Andrew Koenig's
reply stated (I hope).

Ok :), but I will add that value-initialization isn't just for POD's,
it applies to any "non-union class type" without used defined
constructors.

#include <iostream>
#include <ostream>
#include <iomanip>
#include <vector>

struct X
{
std::vector< int > vi;
int x;
};

struct Y
{
std::vector< int > vi;
X x;
};

struct Z
{
std::vector< int > vi;
Y y;
};


void messitup()
{
int array[ 1000 ];
for ( int i = 0; i < 1000; ++i )
{
array[ i ] = 0xCCCCCCC;
}
}

bool is_vi()
{
Z z = Z();
return z.y.x.x == 0;
}

bool is_new_vi()
{
Z *z = new Z();
return z->y.x.x == 0;
}


int main()
{
messitup();

std::cout
<< "value-initialization: "
<< std::boolalpha << is_vi()
<< std::endl
;

std::cout
<< "fake-value-initialization: "
<< std::boolalpha << is_new_vi()
<< std::endl
;
}

1 out of 4 of my compilers returned true, true, 1 returned false, true.
I'm a bit dissapointed gcc 3.4 doesn't support this.

Rob.
 
R

Razvan

Andrew Koenig said:
Yes, but it is very rare that you should care.

If you say "new X", the initial value of the object allocated is the same as
an uninitialized local variable of the same type would have. So, for

This is valid only for the above mentioned POD type. For a
class the call new MyClass is the same with the call new MyClass()
(assuming the class has a default constructor). At least this is what
I understood from you and the previoud posters.

I am rewritting your expression: when calling new X (X is a POD
type) a new object X is created that it is not innitialized.

example, the result of "new int" is the address of an uninitialized int, and
the result of "new std::string" is the address of a std::string object with
no characters (because all strings are initialized, if only by the default
constructor). In contrast, the result of "new int()" is the address of an
int with value 0, and the result of "new std::string()" is exactly the same
as the result of "new std::string" (because all strings are initialized, if
only by the default constructor).

I see. For a POD (like an int) the call new int return a
pointer to an int that is not innitialized (it is not guaranteed to be
zero). OTOH new int() guarantees that the pointer points to an int
innitialized with zero.
For a string it does not matter how you create it because it
is a class that has a constructor and the constructor is called
anyway.

Bottom line:

int* pInt = new int; // the pointer points to an unnitialized int
int* pInt2 = new int() // the pointer points to an int that is
guaranteed to be innitialized to 0
MyClass tst = new MyClass;

is identical with:

MyClass tst2 = new MyClass();

This is a relatively recent feature, so if you write a program that relies
on it, you may wish to make sure that your compiler implements it correctly.

I see. Thanks for the advice.




Regards,
Razvan
 
A

Andrew Koenig

Razvan said:
"Andrew Koenig" <[email protected]> wrote in message
This is valid only for the above mentioned POD type. For a
class the call new MyClass is the same with the call new MyClass()
(assuming the class has a default constructor). At least this is what
I understood from you and the previoud posters.

That is true, but it is also what I said. Please read it again. For
example:

class Foo { Foo(); /* whatever else you like */ };

In this case, the value of the expression "new Foo" is a pointer to an
object of type Foo that has the same value that an otherwise uninitialized
local variable of type Foo has, namely whatever value is obtained by running
the Foo constructor.
So I stand by my original statement.
I am rewritting your expression: when calling new X (X is a POD
type) a new object X is created that it is not innitialized.

This extra qualification is not necessary.
I see. For a POD (like an int) the call new int return a
pointer to an int that is not innitialized (it is not guaranteed to be
zero). OTOH new int() guarantees that the pointer points to an int
innitialized with zero.
Correct.

For a string it does not matter how you create it because it
is a class that has a constructor and the constructor is called
anyway.

Also correct.
Bottom line:
int* pInt = new int; // the pointer points to an unnitialized int
int* pInt2 = new int() // the pointer points to an int that is
guaranteed to be innitialized to 0
MyClass tst = new MyClass;

is identical with:

MyClass tst2 = new MyClass();

Only if you have explicitly defined a constructor for MyClass.

Here is the interesting case:

struct Foo {
int i;
string s;
};

Now "new Foo" yields a pointer to a Foo object in which member s is empty
and member i is uninitialized, whereas "new Foo()" yields a pointer to a Foo
object in which member s is empty and member i is zero. Note that Foo is
not a POD type. Nevertheless, the behavior of "new Foo" differs from that
of "new Foo()".
 
M

Mathieu Malaterre

Just for fun:

http://www.horstmann.com/cpp/pitfalls.html
Constructor pitfalls
Example:

int main()
{ string a("Hello");
string b();
string c = string("World");
// ...
return 0;
}


Pitfall:

string b();

This expression does not construct an object b of type string. Instead,
it is the prototype for a function b with no arguments and return type
string.

Moral: Remember to omit the ( ) when invoking the default constructor.

The C feature of declaring a function in a local scope is worthless
since it lies about the true scope. Most programmers place all
prototypes in header files. But even a worthless feature that you never
use can haunt you.


That mean you should better use new X

Mathieu
 
M

Mathieu Malaterre

Andrew said:

For being consistant , look:

string s1
string s2 = new string

or

string s1();//<- won't work
string *s2 = new string()

....
Mathieu
 
A

Andrew Koenig

For being consistant , look:
string s1
string s2 = new string

string s1();//<- won't work
string *s2 = new string()

So what? Why is such consistency important?

To put it another way: Consider a class T written by someone else. You are
saying that I should never write

T* tp = new T();

In order to make such a claim credible, you have to tell me what you think I
should write instead. The closest alternative I can think of is

T* tp = new T;
*tp = T();

However, in addition to being more verbose and taking more time to run, this
alternative requires that class T have an assignment operator defined, a
requirement that the first alternative does not share.

So if you are telling me that I should not write the first example above
because of a theoretical concern about "consistency" that doesn't actually
apply in this case, what do you recommend that I do instead?
 
R

Razvan

In this case, the value of the expression "new Foo" is a pointer to an
object of type Foo that has the same value that an otherwise uninitialized
local variable of type Foo has, namely whatever value is obtained by running
the Foo constructor.
So I stand by my original statement.

I do not understand. After running the constructor the object
is innitialized.

Only if you have explicitly defined a constructor for MyClass.

How about the default constructor ?
Perhaps I am missing something here. Let's suppose I have the
class:

class CTest
{
int counter;

CTest(){}
}


The constructor for CTest does not innitialize the variable
counter. If I create an object:

CTest test;

is the attribute counter guaranteed to be 0 ? (I mean the constructor
does nothing about it; what is happening is this case?)




Regards,
Razvan
 
A

Andrew Koenig

I do not understand. After running the constructor the object
is innitialized.

Right. In other words, the result of executing "new Foo" is a pointer to an
object that is initialized in exactly the same way as a local variable
without an explicit initializer, in other words:

{
Foo x;
// ...
}

In both cases (i.e. the local variable x, which has no explicit initializer,
and the object created by "new Foo", which also has no explicit
initializer), the object in question is initialized in the same way (i.e. as
specified by the constructor of class Foo).
How about the default constructor ?
Perhaps I am missing something here. Let's suppose I have the
class:

class CTest
{
int counter;

CTest(){}
}

You have defined a constructor for class CTest.
The constructor for CTest does not innitialize the variable
counter. If I create an object:

CTest test;

is the attribute counter guaranteed to be 0 ? (I mean the constructor
does nothing about it; what is happening is this case?)

No. You wrote a constructor, and that constructor doesn't initialize the
member "counter", so it's not initialized.
(unless the object in question is static, in which case all data members are
zero-initialized before running the constructor--but that's not what we're
talking about here).

The important case is this one:

class STest {
int counter;
string xyzzy;
};

STest test;

Here, you did not define a constructor for STest, but it effectively has one
anyway, by virtue of having a data member with a constructor. Accordingly,
if "test" is a local variable, the value of test.counter will be undefined.
On the other hand, if you write

STest *p = new STest();

then p will point to an STest object with its counter member initialized to
zero.
 
K

Karl Heinz Buchegger

Andrew said:
The important case is this one:

class STest {
int counter;
string xyzzy;
};

STest test;

Here, you did not define a constructor for STest, but it effectively has one
anyway, by virtue of having a data member with a constructor. Accordingly,
if "test" is a local variable, the value of test.counter will be undefined.
On the other hand, if you write

STest *p = new STest();

then p will point to an STest object with its counter member initialized to
zero.

Sure about that?
As I see it: STest is not a POD (due to string member xyzzy), thus
the zero initialization does not happen.
If STest would look like this

class STest {
int counter;
char* xyzzy;
};

then

STest *p = new STest();

would initialize counter and xyzzy to 0

( I really hate this rule. If it would be dropped from C++ I wouldn't
leave a single tear for it. Same for implicite return 0 in main() :)
 
V

Victor Bazarov

Karl said:
Sure about that?
As I see it: STest is not a POD (due to string member xyzzy), thus
the zero initialization does not happen.
If STest would look like this

class STest {
int counter;
char* xyzzy;
};

then

STest *p = new STest();

would initialize counter and xyzzy to 0

( I really hate this rule. If it would be dropped from C++ I wouldn't
leave a single tear for it. Same for implicite return 0 in main() :)

Let's analyse... Unless something is different in the new edition (which
I don't have), here we go:

The default-initialisation is happening for the () form of the
new-initialiser (see 5.3.4/15). That means that for an object of
a class type (not POD, as you mentioned), the default constructor is
called (see 8.5/5). The implicitly defined default constructor behaves
like a user-defined default constructor with an _empty_ initialiser list
(see 12.1/7). If a member is not named in the initialser list (see
12.6.2/4) and it is non-POD (as std::string is) it is default-initialised,
and if it's a POD (like int), it's _uninitialised_.

You're correct, at least where the 1998 version of the Standard is used.
Andrew may or may not be mistaken, we better look in the new edition.

Anybody?

Victor
 
A

Andrew Koenig

Let's analyse... Unless something is different in the new edition (which
I don't have), here we go:

Something is different in the new edition. I know because I wrote the
proposal for the change.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,173
Messages
2,570,938
Members
47,473
Latest member
pioneertraining

Latest Threads

Top