Topic: deleting a pointer to built-in type after a cast


Author: Allan_W@my-dejanews.com (Allan W)
Date: Wed, 15 May 2002 17:47:32 GMT
Raw View
Francis Glassborow <francis.glassborow@ntlworld.com> wrote
> Giovanni Bajo <giovannibajo@REMOVEliberoTHIS.it> writes
> >Now, it seems to me that the new operator for built-in types does not do
> >anything more than calling the allocator function. And the delete operator
> >for built-in types does not do anything more than calling the deallocator
> >function. So, why am I not allowed to cast the return of a new[] to any
> >other type I want, and then delete[] it with this new pointer? It looks like
> >a completely useless constraint to me.
>
> You are making assumptions about how these are provided by the
> implementor. The built in allocator returns a block of memory, the new[]
> expression may use part of that for its own purposes and then have to
> appropriately align the remainder for the array type. It might use
> different alignments for different built in types. In such a case
> delete[] expression has got to correctly compute the pointer it passes
> to operator delete[].

Isn't it also true that built-in types may need to do some initialization?

    double *x = new double[2];
    std::cout << x[1];

Is this program allowed to crash? Or does it have to output some
(unspecified) number? If it's the latter, then please note there are
some systems where not all bit patterns are legal values of type double.
That means that new double[] needs to initialize the memory with some
legal value, or at least double-check that the value there is
already legal and not NAN or INF or any of the other values that aren't
supposed to happen.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "AT" <coveraaten@imation.com>
Date: Tue, 14 May 2002 17:50:59 GMT
Raw View

--
_________________
Remove "cover" when reply.
"Giovanni Bajo" <giovannibajo@REMOVEliberoTHIS.it> wrote in message
news:D0DC8.36303$5k4.790749@twister2.libero.it...
>
> "Bob Hairgrove" <rhairgroveNoSpam@Pleasebigfoot.com> ha scritto nel
> messaggio news:3cd3d28d.14466451@news.ch.kpnqwest.net...
>
> > The issues with new[] and delete[] are different than with the
> > non-array types because of the difference in element size.
> >
> > When you call operator new(size_t), you receive a void* because it
> > merely allocates the memory and doesn't construct an object.
> > Presumably, operator delete is expecting a void* as well, so it will
> > de-allocate the correct number of bytes regardless of whatever type
> > the original pointer was cast to.
>
> Ok, I'm quite used to the semantic difference between the allocation
> functions and the new operator.
>
> What I can't understand is why the standard should enforce this
constraint.
> We said that it is legal to call the allocator, cast it to whatever
built-in
> type you want, use it, and then deallocate the memory with the deallocator
> function. This has been confirmed to be legal.
>
> Now, it seems to me that the new operator for built-in types does not do
> anything more than calling the allocator function. And the delete operator
> for built-in types does not do anything more than calling the deallocator
> function. So, why am I not allowed to cast the return of a new[] to any
> other type I want, and then delete[] it with this new pointer? It looks
like
> a completely useless constraint to me.
>
> Giovanni Bajo
>

It is not exactly like that.
First there are new operator we typically use, and operator new.

new operator calls operator new to get memeory allocation then it calls
CONSTRUCTOR of the type you are trying to create.

As you may exect the destructor should be called before deletion.
and if you rudely recast the memory and assign to a different pointer there
is now way
to ensure call to a proper destructor.

This one reason. Another reason. That system actually keep track how many
bytes were allocated and how many bytes goes to single element. So you may
move along the array using poiters arithmetics. All this information is
stored somewhere and the only way to get access to this information is to
ensure (secure) that you deleting what you created but not recast.

If want another reason see C++ headers on memory allocation (paticularly
debug version). Heap is implemented as a list with bunch information stored
there partically to provide means for memory debuging but partly to provide
language features - like delete[]. You may be notice that you don't need to
provide amount of element and their size to delete.

Arkady


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Giovanni Bajo" <giovannibajo@REMOVEliberoTHIS.it>
Date: Fri, 10 May 2002 08:34:30 GMT
Raw View
"Bob Hairgrove" <rhairgroveNoSpam@Pleasebigfoot.com> ha scritto nel
messaggio news:3cd3d28d.14466451@news.ch.kpnqwest.net...

> The issues with new[] and delete[] are different than with the
> non-array types because of the difference in element size.
>
> When you call operator new(size_t), you receive a void* because it
> merely allocates the memory and doesn't construct an object.
> Presumably, operator delete is expecting a void* as well, so it will
> de-allocate the correct number of bytes regardless of whatever type
> the original pointer was cast to.

Ok, I'm quite used to the semantic difference between the allocation
functions and the new operator.

What I can't understand is why the standard should enforce this constraint.
We said that it is legal to call the allocator, cast it to whatever built-in
type you want, use it, and then deallocate the memory with the deallocator
function. This has been confirmed to be legal.

Now, it seems to me that the new operator for built-in types does not do
anything more than calling the allocator function. And the delete operator
for built-in types does not do anything more than calling the deallocator
function. So, why am I not allowed to cast the return of a new[] to any
other type I want, and then delete[] it with this new pointer? It looks like
a completely useless constraint to me.

Giovanni Bajo

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Francis Glassborow <francis.glassborow@ntlworld.com>
Date: Mon, 13 May 2002 17:18:49 GMT
Raw View
In article <D0DC8.36303$5k4.790749@twister2.libero.it>, Giovanni Bajo
<giovannibajo@REMOVEliberoTHIS.it> writes
>Now, it seems to me that the new operator for built-in types does not do
>anything more than calling the allocator function. And the delete operator
>for built-in types does not do anything more than calling the deallocator
>function. So, why am I not allowed to cast the return of a new[] to any
>other type I want, and then delete[] it with this new pointer? It looks like
>a completely useless constraint to me.

You are making assumptions about how these are provided by the
implementor. The built in allocator returns a block of memory, the new[]
expression may use part of that for its own purposes and then have to
appropriately align the remainder for the array type. It might use
different alignments for different built in types. In such a case
delete[] expression has got to correctly compute the pointer it passes
to operator delete[].



--
Francis Glassborow      ACCU
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Giovanni Bajo" <giovannibajo@REMOVEliberoTHIS.it>
Date: Thu, 2 May 2002 18:14:54 CST
Raw View
Is this allowed, or ill-formed?

unsigned int* a = new unsigned int[1000];
unsigned char* b = reinterpret_cast<unsigned char*>(a);
delete [] b;

And what if I casted to void*?

Giovanni

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Matt Ferreira" <mferreira@comcast.net>
Date: Fri, 3 May 2002 20:02:24 GMT
Raw View
> unsigned int* a = new unsigned int[1000];
> unsigned char* b = reinterpret_cast<unsigned char*>(a);
> delete [] b;

Sure. This is allowed. Make sure that you don't try to access a though.

> And what if I casted to void*?

You can delete a void pointer, but this is not necessarily safe. For
example:

class stuff
{
  // some stuff

  ~stuff();
};

void* pStuff = new stuff;
delete pStuff;

The destructor will not be called because pStuff is a void pointer.

Hope this help you out.


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Ron Natalie <ron@sensor.com>
Date: Fri, 3 May 2002 20:02:15 GMT
Raw View

Giovanni Bajo wrote:
>
> Is this allowed, or ill-formed?
>
> unsigned int* a = new unsigned int[1000];
> unsigned char* b = reinterpret_cast<unsigned char*>(a);
> delete [] b;
>
> And what if I casted to void*?
>
> Giovanni

It's not ill-formed, but it ain't allowed.  You must feed
delete[] the exact same value and TYPE that you got from new[].

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: rhairgroveNoSpam@Pleasebigfoot.com (Bob Hairgrove)
Date: Fri, 3 May 2002 20:53:33 GMT
Raw View
On Thu,  2 May 2002 23:14:47 GMT, "Giovanni Bajo"
<giovannibajo@REMOVEliberoTHIS.it> wrote:

>Is this allowed, or ill-formed?
>
>unsigned int* a = new unsigned int[1000];
>unsigned char* b = reinterpret_cast<unsigned char*>(a);
>delete [] b;

I believe the expression is "undefined behaviour". Almost anything and
everything is "allowed", but whether it will work properly or not is
another question. You should only call delete (or delete[]) on the
same object you get from calling new (or new[]).

Since the above is legal C++ syntax, it will compile, and I would say
it's therefore not "ill-formed" ... just broken <g>.

>
>And what if I casted to void*?
>

The same.


Bob Hairgrove
rhairgroveNoSpam@Pleasebigfoot.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Ron Natalie <ron@sensor.com>
Date: Fri, 3 May 2002 22:45:14 GMT
Raw View

Matt Ferreira wrote:
>
> > unsigned int* a = new unsigned int[1000];
> > unsigned char* b = reinterpret_cast<unsigned char*>(a);
> > delete [] b;
>
> Sure. This is allowed. Make sure that you don't try to access a though.

It's undefined behavior.  You must feed delete[] the same typed thing you
allocated

> You can delete a void pointer, but this is not necessarily safe. For
> The destructor will not be called because pStuff is a void pointer.

It's not safe because it's undefined behavior.  Worse things can and
do happen other than the destructor not running.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Giovanni Bajo" <giovannibajo@REMOVEliberoTHIS.it>
Date: Sat, 4 May 2002 11:55:28 GMT
Raw View
"Ron Natalie" <ron@sensor.com> ha scritto nel messaggio
news:3CD1CCBA.54BE7740@sensor.com...

> > unsigned int* a = new unsigned int[1000];
> > unsigned char* b = reinterpret_cast<unsigned char*>(a);
> > delete [] b;
> >
> > And what if I casted to void*?
> >
> > Giovanni
>
> It's not ill-formed, but it ain't allowed.  You must feed
> delete[] the exact same value and TYPE that you got from new[].

Ok, I found something along these lines in 5.3.5p3. I read: "In the second
alternative (delete array) if the dynamic type of the object to be deleted
differs from its static type, the behaviour is undefined". Is it correct to
say that in the above example, "*b" has static type "unsigned char" and
dynamic type "unsigned int"? I thought this could be applied only to the
inheritance relations. So, I'm not sure if we can say that in the above
example the "static type" of b differs from its dynamic type. If it doesn't
differ, then the program does not have undefined behaviour, since the only
other restriction is in p2, and says: "the value of the operand of delete
shall be the pointer value which resulted from a previous array
new-expression", which is of course verified.

To make things even more complicated, what about this:

unsigned int* a = reinterpret_cast<unsigned int*>(operator new(1000));
operator delete(a);

Here, I'm using directly the allocation/deallocation functions. The program
is well-formed, and I can't find anything in the standard that claims
undefined behaviour. I'm not sure why the standard should allow the latter
and disallow the former.

Notice that this whole issue is about POD, POD-structs, POD-unions.
Everything else of course requires a stricter syntax (since the delete
expression invokes the destructor of the object, which must be correctly
accessible).

Giovanni Bajo

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: rhairgroveNoSpam@Pleasebigfoot.com (Bob Hairgrove)
Date: Tue, 7 May 2002 15:34:55 GMT
Raw View
On Sat,  4 May 2002 11:55:28 GMT, "Giovanni Bajo"
<giovannibajo@REMOVEliberoTHIS.it> wrote:

>
>"Ron Natalie" <ron@sensor.com> ha scritto nel messaggio
>news:3CD1CCBA.54BE7740@sensor.com...
>
>> > unsigned int* a = new unsigned int[1000];
>> > unsigned char* b = reinterpret_cast<unsigned char*>(a);
>> > delete [] b;
>> >
>> > And what if I casted to void*?
>> >
>> > Giovanni
>>
>> It's not ill-formed, but it ain't allowed.  You must feed
>> delete[] the exact same value and TYPE that you got from new[].
>
>Ok, I found something along these lines in 5.3.5p3. I read: "In the second
>alternative (delete array) if the dynamic type of the object to be deleted
>differs from its static type, the behaviour is undefined". Is it correct to
>say that in the above example, "*b" has static type "unsigned char" and
>dynamic type "unsigned int"? I thought this could be applied only to the
>inheritance relations. So, I'm not sure if we can say that in the above
>example the "static type" of b differs from its dynamic type. If it doesn't
>differ, then the program does not have undefined behaviour, since the only
>other restriction is in p2, and says: "the value of the operand of delete
>shall be the pointer value which resulted from a previous array
>new-expression", which is of course verified.
>

Dynamic type only applies to objects with virtual functions, AFAIK.
This would rule out any built-in types.

>To make things even more complicated, what about this:
>
>unsigned int* a = reinterpret_cast<unsigned int*>(operator new(1000));
>operator delete(a);
>

The issues with new[] and delete[] are different than with the
non-array types because of the difference in element size.

When you call operator new(size_t), you receive a void* because it
merely allocates the memory and doesn't construct an object.
Presumably, operator delete is expecting a void* as well, so it will
de-allocate the correct number of bytes regardless of whatever type
the original pointer was cast to.

>Here, I'm using directly the allocation/deallocation functions. The program
>is well-formed, and I can't find anything in the standard that claims
>undefined behaviour. I'm not sure why the standard should allow the latter
>and disallow the former.
>

As someone else (I think it was Bart Kowalski) took the trouble to
explain to me in a different thread (possibly in comp.lang.c++), it's
unfortunate that both the allocator function and the new operator both
have the same name, because they do different things. This is why one
is allowed and the other not ... or that's at least the way I
understand it.


Bob Hairgrove
rhairgroveNoSpam@Pleasebigfoot.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Ron Natalie <ron@sensor.com>
Date: Wed, 8 May 2002 02:24:27 GMT
Raw View

Giovanni Bajo wrote:

>
> Ok, I found something along these lines in 5.3.5p3. I read: "In the second
> alternative (delete array) if the dynamic type of the object to be deleted
> differs from its static type, the behaviour is undefined".

No, back up to p2:  The value is required to be that returned by new or
(in the non-array case, a base class pointer of that object).  This
in itself precludes using the value casted to some other type.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]