Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > why is int a[0] not allowed, but int* a = new int[0] is?

Reply
Thread Tools

why is int a[0] not allowed, but int* a = new int[0] is?

 
 
haijin.biz@gmail.com
Guest
Posts: n/a
 
      04-14-2007
I tried the following code and found that the form

#include <iostream>
using namespace std;

int main(int argc, char** argv)
{
//int a[0]; // error C2466: cannot allocate an array of constant size
0
int* b = new int[0];

b[0]=123; // why we can play with b[0] and b[1] as if we had
allocated space for 2 ints?
b[1]=456;
/// b[2]=789; // error

cout<<b[0]<<endl;
cout<<b[1]<<endl;

delete [] b;

return 0;
}

 
Reply With Quote
 
 
 
 
Bo Persson
Guest
Posts: n/a
 
      04-14-2007
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:
:: I tried the following code and found that the form
::
:: #include <iostream>
:: using namespace std;
::
:: int main(int argc, char** argv)
:: {
:: //int a[0]; // error C2466: cannot allocate an array of constant size
:: 0

Zero size objects are not allowed. This is from the C part of the language.

:: int* b = new int[0];

This is from the C++ only part of the language. It don't know why, but it
was decided that this should work.

We know that it was intentional, because the standard says that if you do

int* b = new int[0];
int* c = new int[0];

the pointers b and c have different values.

::
:: b[0]=123; // why we can play with b[0] and b[1] as if we had
:: allocated space for 2 ints?
:: b[1]=456;
:: /// b[2]=789; // error

They are all errors!

You are not allowed to "play" with anything outside the size of the object.
None in this case.

::
:: cout<<b[0]<<endl;
:: cout<<b[1]<<endl;

Can't do that either, there are no elements in b.

::
:: delete [] b;
::
:: return 0;
:: }


Bo Persson


 
Reply With Quote
 
 
 
 
haijin.biz@gmail.com
Guest
Posts: n/a
 
      04-14-2007

> :: b[0]=123; // why we can play with b[0] and b[1] as if we had
> :: allocated space for 2 ints?
> :: b[1]=456;
> :: /// b[2]=789; // error
>
> They are all errors!
>
> You are not allowed to "play" with anything outside the size of the object.
> None in this case.
>
> ::
> :: cout<<b[0]<<endl;
> :: cout<<b[1]<<endl;
>
> Can't do that either, there are no elements in b.


> Bo Persson



Thanks Bo. I understand that it may be the problem of a particular c++
complier for allowing

b[0] = 1;
b[1] = 2;

when all we did before that is int* b = new int[0].

I am using VS 2005 and two assignments are okay, although I think it
must crash the program.



 
Reply With Quote
 
Bo Persson
Guest
Posts: n/a
 
      04-14-2007
(E-Mail Removed) wrote:
::::: b[0]=123; // why we can play with b[0] and b[1] as if we had
::::: allocated space for 2 ints?
::::: b[1]=456;
::::: /// b[2]=789; // error
:::
::: They are all errors!
:::
::: You are not allowed to "play" with anything outside the size of the
::: object. None in this case.
:::
:::::
::::: cout<<b[0]<<endl;
::::: cout<<b[1]<<endl;
:::
::: Can't do that either, there are no elements in b.
::
::: Bo Persson
::
::
:: Thanks Bo. I understand that it may be the problem of a particular
:: c++ complier for allowing
::
:: b[0] = 1;
:: b[1] = 2;
::
:: when all we did before that is int* b = new int[0].
::
:: I am using VS 2005 and two assignments are okay, although I think it
:: must crash the program.

It doesn't have to. Assigning outside the size of an array is "undefined
behaviour" in C++ speak. That means that it might crash, or seems to work,
or something else. The language standard doesn't say what must happen, just
that you shouldn't do it.


Bo Persson


 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      04-14-2007
On Apr 14, 8:07 am, "Bo Persson" <(E-Mail Removed)> wrote:
> (E-Mail Removed) wrote:


> :: I tried the following code and found that the form


> :: #include <iostream>
> :: using namespace std;


> :: int main(int argc, char** argv)
> :: {
> :: //int a[0]; // error C2466: cannot allocate an array of constant size
> :: 0


> Zero size objects are not allowed. This is from the C part of
> the language.


It's not just a question of size. The standard explicitly says
that using 0 here is forbidden.

> :: int* b = new int[0];


> This is from the C++ only part of the language. It don't know
> why, but it was decided that this should work.


Because it's sometimes useful. Not "new int[0]", of course, but
"new int[n]", where n may sometimes take the value of 0. It's
not allowed for arrays not allocated dynamically, because the
dimension there must be a constant, and it's not really useful
to have an array whose size it *always* 0.

Note that this corresponds exactly to the situation in C, where
you can malloc 0 bytes.

> We know that it was intentional, because the standard says that if you do


> int* b = new int[0];
> int* c = new int[0];


> the pointers b and c have different values.


They're different arrays (objects), and so must have different
addresses.

> :: b[0]=123; // why we can play with b[0] and b[1] as if we had
> :: allocated space for 2 ints?
> :: b[1]=456;
> :: /// b[2]=789; // error


> They are all errors!


> You are not allowed to "play" with anything outside the size
> of the object. None in this case.


You're not even allowed to create a pointer to more than one
past the end---the expression b+2 is illegal.

Of course, it's undefined behavior, so it might seem to work.
(In my experience, undefined behavior usually works perfectly in
all my tests, and then fails in the most visually possible
manner in the demo in front of the important customer.)

--
James Kanze (Gabi Software) email: (E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

 
Reply With Quote
 
zeppe
Guest
Posts: n/a
 
      04-14-2007
James Kanze wrote:

>> This is from the C++ only part of the language. It don't know
>> why, but it was decided that this should work.

>
> Because it's sometimes useful. Not "new int[0]", of course, but
> "new int[n]", where n may sometimes take the value of 0. It's
> not allowed for arrays not allocated dynamically, because the
> dimension there must be a constant, and it's not really useful
> to have an array whose size it *always* 0.


Yes, and particularly it has to be highlighted the difference in meaning
between

int b[100];

and

int* b = new int[100];

the first is a statically allocated object into the stack, and his type
is "int [100]", so of course a type of "int [0]" would not have any
meaning. In the second case, on the other hand, we are just allocating
some memory through the operator new for the double. The syntax is
similar, but the behaviour is really different, being 100 the argument
of a function, and being evaluated at run time. Basically, there is no
way to check the size at compilation time in general

> Note that this corresponds exactly to the situation in C, where
> you can malloc 0 bytes.


Because there is no way to avoid it. In the C standard, however, the
result is implementation defined.


Regards,

Zeppe
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      04-14-2007
On Apr 14, 10:26 pm, zeppe <(E-Mail Removed)>
wrote:
> James Kanze wrote:
> >> This is from the C++ only part of the language. It don't know
> >> why, but it was decided that this should work.


> > Because it's sometimes useful. Not "new int[0]", of course, but
> > "new int[n]", where n may sometimes take the value of 0. It's
> > not allowed for arrays not allocated dynamically, because the
> > dimension there must be a constant, and it's not really useful
> > to have an array whose size it *always* 0.


> Yes, and particularly it has to be highlighted the difference in meaning
> between


> int b[100];


> and


> int* b = new int[100];


> the first is a statically allocated object into the stack,


If it's on the stack, it's not statically allocated. The
important difference in this case is that the first requires a
compile time constant; if it is 0 once, it will be zero every
time, and that doesn't make sense. In the second, the dimension
can be a variable, the result of an expression, and it's useful
in such cases to not have to treat 0 as a special case.

> and his type is "int [100]", so of course a type of "int [0]"
> would not have any meaning. In the second case, on the other
> hand, we are just allocating some memory through the operator
> new for the double.


And the type of the memory we allocate is int[0].

> The syntax is
> similar, but the behaviour is really different, being 100 the argument
> of a function, and being evaluated at run time. Basically, there is no
> way to check the size at compilation time in general


No. And because the type is unsigned, there's no way to check
for accidentally negative values, ever.

> > Note that this corresponds exactly to the situation in C, where
> > you can malloc 0 bytes.


> Because there is no way to avoid it. In the C standard, however, the
> result is implementation defined.


Yes, and the C++ standard corrected this bug.

--
--
James Kanze (Gabi Software) email: (E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

 
Reply With Quote
 
Zeppe
Guest
Posts: n/a
 
      04-16-2007
James Kanze wrote:

>> int b[100];

>
>> and

>
>> int* b = new int[100];

>
>> the first is a statically allocated object into the stack,

>
> If it's on the stack, it's not statically allocated.


Ops! I wanted to say "allocated in the static memory"

> The
> important difference in this case is that the first requires a
> compile time constant; if it is 0 once, it will be zero every
> time, and that doesn't make sense.


that's because, being allocated into the stack, the type is resolved at
compile time.

> In the second, the dimension
> can be a variable, the result of an expression, and it's useful
> in such cases to not have to treat 0 as a special case.


Which is not possible at compile time, anyway.

>> and his type is "int [100]", so of course a type of "int [0]"
>> would not have any meaning. In the second case, on the other
>> hand, we are just allocating some memory through the operator
>> new for the double.

>
> And the type of the memory we allocate is int[0].


Well, that is not so clear according to me. I mean, probably the most
rigorous way to see the problem is that one, but you can't access to
that type if it is in the dynamic memory, so basically the real type is
hidden. You will have just a pointer. Additionally, we don't have any
dynamic type for anything but virtual classes, so there is no int [n]
type if n is not constant. Of course IMHO.

Regards,

Zeppe
 
Reply With Quote
 
Mike Smith
Guest
Posts: n/a
 
      04-16-2007
(E-Mail Removed) wrote:
>> :: b[0]=123; // why we can play with b[0] and b[1] as if we had
>> :: allocated space for 2 ints?
>> :: b[1]=456;
>> :: /// b[2]=789; // error
>>
>> They are all errors!
>>
>> You are not allowed to "play" with anything outside the size of the object.
>> None in this case.
>>
>> ::
>> :: cout<<b[0]<<endl;
>> :: cout<<b[1]<<endl;
>>
>> Can't do that either, there are no elements in b.

>
>> Bo Persson

>
>
> Thanks Bo. I understand that it may be the problem of a particular c++
> complier for allowing
>
> b[0] = 1;
> b[1] = 2;
>
> when all we did before that is int* b = new int[0].
>
> I am using VS 2005 and two assignments are okay, although I think it
> must crash the program.


Just because the program does not happen to crash, doesn't mean you're
not doing something illegal. b[0] and b[1] and both out-of-range
references in your program; it's just dumb luck that your program
doesn't crash.

--
Mike Smith
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      04-17-2007
On Apr 16, 12:19 pm, Zeppe
<(E-Mail Removed)> wrote:
> James Kanze wrote:


[...]
> >> and his type is "int [100]", so of course a type of "int [0]"
> >> would not have any meaning. In the second case, on the other
> >> hand, we are just allocating some memory through the operator
> >> new for the double.


> > And the type of the memory we allocate is int[0].


> Well, that is not so clear according to me. I mean, probably the most
> rigorous way to see the problem is that one, but you can't access to
> that type if it is in the dynamic memory, so basically the real type is
> hidden.


The fact that you cannot access it is linked to this type. If
the type were int[1], then p[0] would be legal. Since the type
is int[0], it's not.

Of course, the result of the new expression is type int*, so
some vital type information has been lost.

> You will have just a pointer.


The new expression returns a pointer. The memory which it
allocates has a type, however, which is not the type of the
pointer. (This is how new differs from malloc, for example.)

> Additionally, we don't have any
> dynamic type for anything but virtual classes, so there is no int [n]
> type if n is not constant. Of course IMHO.


That's an interesting observation. The problem is that "dynamic
type" can mean different things. In this case, if I do
something like:

int* p = new int[ i ] ;

each invocation will construct an array with a specific size; an
array with a specific size has a type which includes that size.
Similarly, every object has a type, even if you cannot always
access the information. The case where i is 0 is interesting,
because arguably, you don't have an object.

I still find it cleaner to think of it as having a specific
type. In the general case, it is the type of the actual array
which determines the legal bounds, and I don't see why int[0]
should be an exception: the legal bounds for a T[N] are [0,N)
(and if N is 0, of course, [0,N) is empty).

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Why does "template<typename T> ... function<T(int)>" not match "int(&)(int)" implicitly? Steve Hicks C++ 2 09-28-2009 05:24 PM
findcontrol("PlaceHolderPrice") why why why why why why why why why why why Mr. SweatyFinger ASP .Net 2 12-02-2006 03:46 PM
int a[10]; int* p=(int*)((&a)+1); But why p isn't equal to ((&a)+1)? aling C++ 8 10-20-2005 02:42 PM
int main(int argc, char *argv[] ) vs int main(int argc, char **argv ) Hal Styli C Programming 14 01-20-2004 10:00 PM
dirty stuff: f(int,int) cast to f(struct{int,int}) Schnoffos C Programming 2 06-27-2003 03:13 AM



Advertisments