From: hansen@pegasus.att.com (Tony L. Hansen)
Subject: Re: delete with arrays - help please
Organization: AT&T
Date: Thu, 19 Nov 1992 16:48:00 GMT
Summary: always use delete[] with arrays of all types
Keywords: c++, destructors, delete[], arrays

< From: carroll@sde.mdso.vf.ge.com (Carroll James)
< (via From: srlncnc@gopher.dosli.govt.nz (Chris Crook))
<
< The reason for this is simple. new and delete really use 'malloc' and
< 'free' (or similar systems calls to the heap manager) to allocate a bocks
< of memory.
<
< The heap manager knows how big of a block has been allocated but it DOES
< NOT know anything about data types in those blocks. Because of this the
< call of the destructors is done in C++ and not by the 'system' (in this
< case, the heap manager, which is part of the system).
<
< In older versions of C++ (2.0 ?) you couldnt use a [] without a number in
< it because the delete operator (which is really a library routine in C++)
< didnt get a count from the heap manager. The entire reason for the [n] was
< for the delete operation to call the destructor 'n' times. In newer
< versions of C++ the delete operator became smart enough to know (or to
< figure out based on size of element being deleted and the size of the
< block allocated) what 'n' is and call the destructor that many times.
<
< In either case (i.e. delete x, or delete [n] x) a call is made to 'free'
< (which would look like free(x)) at which point the entire block is freed
< by the heap manager. The problem is that for Object instancted with
< destructors, the destructors will not all be called unless the [n] is
< supplied (remember that delete without [] or [n] assumes there is only
< one).
<
< For built in types or object instances that dont have destructors, the
< total block of memory is freed. Therefore for these instances or built in
< types the overall effect is the same for both 'delete x' and 'delete []
< x'.

There are other implementations of which you are evidently not aware for
which this won't work.

Consider this common implementation:

    Invoking "X *px = new X[10]" will invoke "operator new(sizeof(size_t) +
    sizeof(X)*10)". Into that returned address, the size of the array (10 in
    this case) will be placed into the first four (actually, sizeof(size_t))
    bytes. The function which handles "new X[10]" will then add four bytes
    to the address, invoke the 10 constructors, and then return that new
    address. That is, the address stored into px, as returned by "new
    X[10]", will be four bytes beyond that returned by the "operator new()".

    When "delete[] px" is invoked, delete[] will subtract four bytes from
    the address it's passed, retrieve the count, invoke the destructor on
    those objects, and pass the new address (px-4) to "operator delete()".

    (Most current implementations which use this scheme only do it if the
    class has a destructor, and don't store the count otherwise. But such an
    optimization is not required.)

What happens if you invoke "delete px"? The value passed to "operator
delete()" will NOT be an address that was returned from "operator new()"!

Can you say "core dump"? I knew you could.

< I think ARM mentions some precautions to take. I personally dont like
< making a distinction between built in types and object instances when it
< can be avoided but in this case it will work.

This is all implementation dependent, and on some implementations you may be
able to get away with just invoking "delete px". But don't count on it!

					Tony Hansen
			    hansen@pegasus.att.com, tony@attmail.com
				att!pegasus!hansen, attmail!tony

Newsgroups: comp.lang.c++