Initialized arrays using new

J

John

This produces an initialized array to zero:

int *i = new int[100]() ;

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp

But this doesn't initialize the array. The assembly output is identical.
What's going on?

int *i = new int[100] ;

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp
 
J

John

Phlip said:
John said:
This produces an initialized array to zero:

int *i = new int[100]() ;

What would this do?

int *i = new int[100](42) ;

Produce a compiler error:

error C2075: 'Target of operator new()' : array initialization needs curly braces
 
P

Phlip

John said:
This produces an initialized array to zero:

int *i = new int[100]() ;

What would this do?

int *i = new int[100](42) ;
Produce a compiler error:

error C2075: 'Target of operator new()' : array initialization needs curly
braces

I am aware that this assertion passes:

assert(0 == int());

but it looks like if 'new int[100](42)' cannot create an array of 100 ints
initialized to 42, then 'new int[100]()' is not the same as using new to
create an array of 100 'int()' constructions. It seems that the trailing
'()' is an artifact of 'new's status as a kind of function. You can say 'new
SimCity;' or 'new SimCity()'.

A language lawyer might find actual verbiage on the subject, but I would
just go with a 'std::vector' and 'std::fill()'.
 
J

John

Phlip said:
John said:
This produces an initialized array to zero:

int *i = new int[100]() ;

What would this do?

int *i = new int[100](42) ;
Produce a compiler error:

error C2075: 'Target of operator new()' : array initialization needs curly
braces

I am aware that this assertion passes:

assert(0 == int());

but it looks like if 'new int[100](42)' cannot create an array of 100 ints
initialized to 42, then 'new int[100]()' is not the same as using new to
create an array of 100 'int()' constructions. It seems that the trailing
'()' is an artifact of 'new's status as a kind of function. You can say 'new
SimCity;' or 'new SimCity()'.

A language lawyer might find actual verbiage on the subject, but I would
just go with a 'std::vector' and 'std::fill()'.

I think you missed my original point, why do two different constructs that
produces two different set of results create the identical machine code?


This produces an initialized array to zero:

int *i = new int[100]() ; <-- notice the '()'.

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp

But this doesn't initialize the array. The assembly output is identical.
What's going on?

int *i = new int[100] ; <-- this array is *not* initalized

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp
 
T

Thomas Tutone

John wrote:

[snip]
I think you missed my original point, why do two different constructs that
produces two different set of results create the identical machine code?


This produces an initialized array to zero:

How do you know? Why do you think it was "initialized"? I mean, how
do you know that region of memory didn't, by coincidence, happen to
have zeros in it?
int *i = new int[100]() ; <-- notice the '()'.

[snip]

Best regards,

Tom
 
V

Victor Bazarov

John said:
[..] why do two different constructs
that produces two different set of results create the identical
machine code?

What compiler is that?
This produces an initialized array to zero:

How do you know that it's initialised to 0?
int *i = new int[100]() ; <-- notice the '()'.

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp

This looks like contents of a function. Have you tried actually
_using_ the array contents? The optimiser can discard any code
that has no effect (like setting your array elements to 0).
But this doesn't initialize the array. The assembly output is
identical. What's going on?

Post C++ code, then we can talk.
int *i = new int[100] ; <-- this array is *not* initalized

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp

V
 
J

Jim Langston

Victor Bazarov said:
John said:
[..] why do two different constructs
that produces two different set of results create the identical
machine code?

What compiler is that?
This produces an initialized array to zero:

How do you know that it's initialised to 0?
int *i = new int[100]() ; <-- notice the '()'.

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp

This looks like contents of a function. Have you tried actually
_using_ the array contents? The optimiser can discard any code
that has no effect (like setting your array elements to 0).
But this doesn't initialize the array. The assembly output is
identical. What's going on?

Post C++ code, then we can talk.
int *i = new int[100] ; <-- this array is *not* initalized

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp

V

On my system I tried this:
int* MyArray = new int[10];
std::cout << MyArray[0] << std::endl;
delete[] MyArray;

MyArray = new int[10]();
std::cout << MyArray[0] << std::endl;
delete[] MyArray;

MyArray = new int[10]();
std::cout << MyArray[0] << std::endl;
delete[] MyArray;

MyArray = new int[10];
std::cout << MyArray[0] << std::endl;
delete[] MyArray;

output was:
-842150451
0
0
-842150451

I then added a few more, didn't delete them til after they were all created,
displayed [2] instead of 0, etc.. but in all cases if the array was in the
syntax new int[10]() the values were always 0, other numbers otherwise
(curiously enough, I was always winding up with -842150451).

This would be a strong indication that it was, in fact, zero initializing
the array. I am not the OP but got curious myself.
 
J

Jim Langston

John said:
This produces an initialized array to zero:

int *i = new int[100]() ;

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp

But this doesn't initialize the array. The assembly output is identical.
What's going on?

Have you looked at the assembly after this? Are you 100% sure that there
isn't some assembly after this iterating through the array and setting the
values to 0?

int *i = new int[100] ;

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp
 
P

Phlip

Jim said:
On my system I tried this:
int* MyArray = new int[10];
std::cout << MyArray[0] << std::endl;

Just a note: The act of rvalue-ing an uninitialized integer is undefined.

(Question: Is this defined?

char f;
assert(0 == f || 0 != f);

I know it's undefined for 'int f'.)

You are correct that you can use this experiment to trivially inspect raw
memory, on most architectures. But the undefinity happens before you even
see the 0 or !0.
 
P

Pete Becker

Phlip said:
Jim Langston wrote:

On my system I tried this:
int* MyArray = new int[10];
std::cout << MyArray[0] << std::endl;


Just a note: The act of rvalue-ing an uninitialized integer is undefined.

(Question: Is this defined?

char f;
assert(0 == f || 0 != f);

I know it's undefined for 'int f'.)

In C it's undefined when f is an int, but well defined when f is any
flavor of char.
You are correct that you can use this experiment to trivially inspect raw
memory, on most architectures. But the undefinity happens before you even
see the 0 or !0.

But "undefined" doesn't mean "must not do what you expect." I know that
the C folks have spent a great deal of time discussing the possibility
of trap values, so I assume there are architectures where they exist,
but I haven't run into any. So it's not an issue I spend time worrying
about.
 
F

Frederick Gotham

John posted:
This produces an initialized array to zero:

int *i = new int[100]() ;


The Standard guarantees this.

But this doesn't initialize the array. The assembly output is identical.
What's going on?

int *i = new int[100] ;


It appears that your compiler initialises all new'd memory to zero
(regardless of whether you ask it to). This is inefficient, yet doesn't
violate any constraits of the Standard.

Perhaps if you switch to Release Mode, it will remove this inefficiency.
 
T

Thomas J. Gritzan

John said:
This produces an initialized array to zero:

int *i = new int[100]() ;
Yes.

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp

<Half-OT>
I don't see any initialization in the assembly code. Perhaups the operator
new does it.

Did you check if the array really is initialized to zero?

What compiler are you using? I think VC6.0 didn't do the zero
initialization is this case.
</>
 
P

Philip Potter

Frederick Gotham said:
It appears that your compiler initialises all new'd memory to zero
(regardless of whether you ask it to). This is inefficient, yet doesn't
violate any constraits of the Standard.

Perhaps if you switch to Release Mode, it will remove this inefficiency.

If the Debug Mode initializes uninitialized memory to 0, that's really poor
design; it makes code work when it really shouldn't. I would have thought a
better move would be to initialize all uninitialized memory to 0xdeadbeef...

Is this common behaviour for IDEs?

Philip
 
J

John

Whoa! My bad! I should have tested the code using more than one compiler.

This is the code:

int *i = new int[20]() ;
for ( int x = 0 ; x < 20 ; x++, cout << i[x] << " " ) ;
cout << endl ;
int *i2 = new int[20] ;
for ( int x = 0 ; x < 20 ; x++, cout << i2[x] << " ") ;
cout << endl ;

These are the results under Visual Studio C++ Express (latest version)

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -33686019
-842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451
-842150451 -842150451 -842150451 -842150451 -842150451 -842150451 -842150451
-842150451 -842150451 -842150451 -842150451 -842150451 -33686019

However, these are the results using BloodShed (version 4.9.9.2):

-1163005939 -1163005939 -1163005939 -1163005939 -1163005939 -1163005939
-1163005939 -1163005939 -1163005939 -1163005939 -1163005939 -1163005939
-1163005939 -1163005939 -1163005939 -1163005939 -1163005939 -1163005939
-1163005939 -1414812757 (interesting that the last element differs)
-1163005939 -1163005939 -1163005939 -1163005939 -1163005939 -1163005939
-1163005939 -1163005939 -1163005939 -1163005939 -1163005939 -1163005939
-1163005939 -1163005939 -1163005939 -1163005939 -1163005939 -1163005939
-1163005939 -1414812757

So, for whatever reason, when I was inspecting the first few results of:

int *i = new int[array_size]()

using Visual Studio, it just happens that all elements of the array (except
for the last element). I didn't check out the entire array before posting my
original note. Dumb, dumb, dumb.

Using this code with Visual Studio, all elements of both arrays (except for
the last element in both cases) are zero.

int *i = new int[1000]() ;
for ( int x = 0 ; x < 1000 ; x++, cout << i[x] << " " ) ;
cout << endl ;
double *d = new double[1000]() ;
for ( int x = 0 ; x < 1000 ; x++, cout << d[x] << " " ) ;
cout << endl ;

I graded my "assignment" an 'A' for Assuming.
 
T

Thomas J. Gritzan

John said:
Whoa! My bad! I should have tested the code using more than one compiler.

This is the code:

int *i = new int[20]() ;
for ( int x = 0 ; x < 20 ; x++, cout << i[x] << " " ) ;
cout << endl ;
int *i2 = new int[20] ;
for ( int x = 0 ; x < 20 ; x++, cout << i2[x] << " ") ;
cout << endl ;

Your loop is wrong. Put the output line between the ')' and the ';'. You
are accessing memory one past the array, which is undefined behaviour.
BloodShed (version 4.9.9.2):

This compiler seems to be not standard conformant.
 
V

Victor Bazarov

Philip said:
If the Debug Mode initializes uninitialized memory to 0, that's
really poor design; it makes code work when it really shouldn't. I
would have thought a better move would be to initialize all
uninitialized memory to 0xdeadbeef...

Is this common behaviour for IDEs?

What does it have to do with IDEs? It's the compilers who are at
fault.

Actually they used to be, and was sometimes a source of trouble. I
do remember chasing down an uninitialised *double* in release mode
on a system with an emulator of FP coprocessor which fell over when
an uninitialised value was "loaded" into its "registers". In debug
mode everything, as you may have guessed, was fine because the same
double was zero-initialised.

At present, since *I* mostly deal with VC++, I know that only newly
allocated memory is initialised with 0xCC octets in debug and filled
with 0xDD on delete, but it only concerns free store. There can be
more, but, honestly, I am too busy to remember all those things.

You know, like they say, just do the right thing and everything is
going to be hunky-dory.

V
 
P

Philip Potter

Victor Bazarov said:
What does it have to do with IDEs? It's the compilers who are at
fault.

You're right, of course. (I've only ever seen a debug/release switch in
compilers attached to IDEs)
Actually they used to be, and was sometimes a source of trouble. I
do remember chasing down an uninitialised *double* in release mode
on a system with an emulator of FP coprocessor which fell over when
an uninitialised value was "loaded" into its "registers". In debug
mode everything, as you may have guessed, was fine because the same
double was zero-initialised.

At present, since *I* mostly deal with VC++, I know that only newly
allocated memory is initialised with 0xCC octets in debug and filled
with 0xDD on delete, but it only concerns free store. There can be
more, but, honestly, I am too busy to remember all those things.

That's good to know about.
You know, like they say, just do the right thing and everything is
going to be hunky-dory.

Heh. If I did the right thing all the time, I wouldn't have any need for
compiler warnings.

Philip
 
G

Greg Comeau

John wrote:
[snip]
I think you missed my original point, why do two different constructs that
produces two different set of results create the identical machine code?


This produces an initialized array to zero:

How do you know? Why do you think it was "initialized"? I mean, how
do you know that region of memory didn't, by coincidence, happen to
have zeros in it?
int *i = new int[100]() ; <-- notice the '()'.

If one has a standard conforming compiler, running in compliant mode,
then John is right that after new int[100]() that the array has
been 0 init'd. It won't be guaranteed w/o the ().
 
J

John

Jim said:
John said:
This produces an initialized array to zero:

int *i = new int[100]() ;

004124B0 push ebp
004124B1 mov ebp,esp
004124B3 mov eax,dword ptr [count]
004124B6 push eax
004124B7 call operator new (411212h)
004124BC add esp,4
004124BF pop ebp

But this doesn't initialize the array. The assembly output is identical.
What's going on?

Have you looked at the assembly after this? Are you 100% sure that there
isn't some assembly after this iterating through the array and setting the
values to 0?


No, I wasn't 100% certain so I looked deeper into the disassembly code
produced from Visual Studio, and by golly, you are correct. This type (new
int[ARRAY_SIZE]()) does in fact call memset initializing the array to zero. 0
is pushed onto the stack in the call to memset.

// snippet from memset
// AL == 0 (value to be set), CX == 0xA (the size of the array)
102308CA shr ecx,2
102308CD je 102308D5
102308CF rep stos dword ptr es:[edi]

void testarray()
{
00411640 push ebp
00411641 mov ebp,esp
00411643 sub esp,10Ch
00411649 push ebx
0041164A push esi
0041164B push edi
0041164C lea edi,[ebp-10Ch]
00411652 mov ecx,43h
00411657 mov eax,0CCCCCCCCh
0041165C rep stos dword ptr es:[edi]
const int ARRAY_SIZE = 10 ;
0041165E mov dword ptr [ARRAY_SIZE],0Ah
int *i = new int[ARRAY_SIZE]() ;
00411665 mov dword ptr [ebp-104h],28h
0041166F mov eax,dword ptr [ebp-104h]
00411675 push eax
00411676 call operator new[] (4110EBh)
0041167B add esp,4
0041167E mov dword ptr [ebp-0F8h],eax
00411684 cmp dword ptr [ebp-0F8h],0
0041168B je testarray+73h (4116B3h)
0041168D mov ecx,dword ptr [ebp-104h]
00411693 push ecx
00411694 push 0
00411696 mov edx,dword ptr [ebp-0F8h]
0041169C push edx
0041169D call @ILT+155(_memset) (4110A0h) ***MEMSET HERE!***
004116A2 add esp,0Ch
004116A5 mov eax,dword ptr [ebp-0F8h]
004116AB mov dword ptr [ebp-10Ch],eax
004116B1 jmp testarray+7Dh (4116BDh)
004116B3 mov dword ptr [ebp-10Ch],0
004116BD mov ecx,dword ptr [ebp-10Ch]
004116C3 mov dword ptr ,ecx
// for ( int x = 0 ; x < ARRAY_SIZE ; x++ )
// cout << i[x] << " " ;
// cout << endl ;
int *i2 = new int[ARRAY_SIZE] ;
004116C6 push 28h
004116C8 call operator new[] (4110EBh)
004116CD add esp,4
004116D0 mov dword ptr [ebp-0ECh],eax
004116D6 mov eax,dword ptr [ebp-0ECh]
004116DC mov dword ptr [i2],eax
// for ( int x = 0 ; x < ARRAY_SIZE ; x++ )
// cout << i2[x] << " " ;
// cout << endl ;


}
004116DF pop edi
004116E0 pop esi
004116E1 pop ebx
004116E2 add esp,10Ch
004116E8 cmp ebp,esp
004116EA call @ILT+435(__RTC_CheckEsp) (4111B8h)
004116EF mov esp,ebp
004116F1 pop ebp
004116F2 ret LEAVE FUNCTION. MEMSET NOT CALLED THIS TIME.
 

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
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top