Topic: new T[0] and sizeof(T)


Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1996/02/01
Raw View
In article 4676@iiasa.ac.at, marek@iiasa.ac.at (Marek  MAKOWSKI) writes:
>I would like to ask for comments on three easy questions illustrated
>by the following piece of code:
>
>template <class I, class T>
>void mVect<I,T>::resize(I new_size) {
>   T *old = v;
>   v = new T[new_size];    // T *v is a private member of mVect
>   int size_of_elem = sizeof(T);    // <--- question 3
>   //
>   // do something
>   //
>   delete[] old;     // <--- questions 1 & 2
>}
>
>I have the following questions:
>1. Is it absolutely robust and portable to delete[] old, even
>   if a previous call was for new_size == 0 (or if v was allocated
>   by the ctor for the size == 0) ?

If you allocate an object with new[], you delete it with delete[]. In
addition, it is always safe to delete a null pointer.

> In other words: is it guaranteed that:
>   (v = new T[0]) == 0;

No. The result of 'new' is never a null pointer (unless the allocation fails
and you are using a pre-exception or "nothrow" version of new). A request of
zero size results in a pointer value distinct from all other pointer values
in the program. So if you write
 T* t1 = new T[count];
 T* t2 = new T[count];
and if the allocations succeed, it must be true that
 ( t1 != 0 && t1 != t2 && t2 != 0 )
even if count is zero. The expression "new T[0]" is invalid, but if you
use a non-const expression for the count, it is OK if the value is zero.

Since you have requested zero objects, you cannot dereference the resulting
pointer -- it might not point at usable storage. But since you acquired the
pointer value from "new" you can (and should) pass it to "delete".

>2. Is it correct to assume that no destructor is called by this statement
> if old was set as: old = new T[0]  ??

As noted above, "new T[0]" isn't valid, but if you ask for zero objects,
no objects are created. When you delete the array, no destructors
should be called. I can believe that a compiler might get some part of
these requirements wrong, since this sort of thing hardly ever happens and
bugs might slip through testing.

>3. Is there any risk involved in using sizeof(T) in this statement ?

If T is a completely-defined type, you can always ask for sizeof(T); its
value is a compile-time constant. I'm afraid I don't understand this
question.

---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy is
  in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]





Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/02/02
Raw View
marek@iiasa.ac.at (Marek  MAKOWSKI) writes:

>I would like to ask for comments on three easy questions illustrated
>by the following piece of code:
>
>template <class I, class T>
>void mVect<I,T>::resize(I new_size) {
>   T *old = v;
>   v = new T[new_size];    // T *v is a private member of mVect
>   int size_of_elem = sizeof(T);    // <--- question 3
>   //
>   // do something
>   //
>   delete[] old;     // <--- questions 1 & 2
>}
>
>I have the following questions:
>1. Is it absolutely robust and portable to delete[] old, even
>   if a previous call was for new_size == 0 (or if v was allocated
>   by the ctor for the size == 0) ?

The code

 T *old = new T[0];
 delete [] old;

is definitely perfectly legal (strictly conforming).

Whether or not it is in practice portable is another question -- that
is something that can only be determined empirically.

> In other words: is it guaranteed that:
>   (v = new T[0]) == 0;

No, after 'v = new T[0]', it is guaranteed that `v' is *not* a null pointer.

>2. Is it correct to assume that no destructor is called by this statement
> if old was set as: old = new T[0]  ??

Yes.

>3. Is there any risk involved in using sizeof(T) in this statement ?

Basically no, but of course that would depend on what you used it for.

>The Watcom code blows-up on the delete[] statement (if a previous
>call was for new_size == 0)

If what you have described is correct, then it sounds like a Watcom bug to me.
(However, I suspect there is a good chance that there is a bug somewhere
in the parts of your code that you haven't shown us.)

>and gives a warning whenever it sees the sizeof(T).

Compilers are allowed to warn about anything they like;
however I don't see why warning about `sizeof(T)' would be useful.

>If the answer for quaestions 1 and 2 is negative then I would like to
>know the reason why the standard does not require new to return 0
>for zero_size array of objects.

Well, an array of size zero is conceptually different to no array at all.

>If there is a good reason for allowing new to return "anything" in such
>situations then one should add to every ctor setting a ptr to 0
>(which indeed made the Watcom version of my application running).

--
Fergus Henderson              WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au               PGP: finger fjh@128.250.37.3

[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy is
  summarized in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
]





Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/02/03
Raw View
clamage@Eng.Sun.COM (Steve Clamage) writes:

>The expression "new T[0]" is invalid, but if you
>use a non-const expression for the count, it is OK if the value is zero.

What makes you think that the expression `new T[0]' is invalid?
As I read the working paper, it seems perfectly legal, and the
three compilers I tried it on were all quite happy to accept it.

--
Fergus Henderson              WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au               PGP: finger fjh@128.250.37.3
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]