Topic: Why no size_t in global operator delete?


Author: Scott Meyers <Usenet@aristeia.com>
Date: Fri, 27 Feb 2004 00:02:54 CST
Raw View
Classes can declare an operator delete that has the runtime system provide
the size of the just-destructed-object whose memory is being deallocated:

  void operator delete(void *ptr, size_t sizeOfFormerObject);

Does anybody know why there is no global operator delete with this same
signature?  A client of mine claims to have a good reason for wanting to
know the size of the memory being deallocated by the global operator
delete, and when he asked me why there was no global version like the class
version taking a size_t, I found that I had no idea why such a version is
missing.  Is there a good technical basis for the omission?

Thanks,

Scott

---
[ 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: "William M. Miller" <wmm@world.std.com>
Date: Fri, 27 Feb 2004 15:03:40 CST
Raw View
Scott Meyers wrote:

> Classes can declare an operator delete that has the runtime system provide
> the size of the just-destructed-object whose memory is being deallocated:
>
>   void operator delete(void *ptr, size_t sizeOfFormerObject);
>
> Does anybody know why there is no global operator delete with this same
> signature?  A client of mine claims to have a good reason for wanting to
> know the size of the memory being deallocated by the global operator
> delete, and when he asked me why there was no global version like the class
> version taking a size_t, I found that I had no idea why such a version is
> missing.  Is there a good technical basis for the omission?

The difference is that a class gives you a way of determining
whether the (void*, size_t) signature is the "usual" deallocation
function or an overload ("placement") version (3.7.3.2p2).  The
two-parameter version is only a "usual" deallocation function if
the class does not declare the single-parameter version.

The global deallocation functions are always declared everywhere
(with one parameter), so a two-parameter version can only be a
"placement" deallocation function.

--
William M. Miller, The MathWorks, Inc.
wmm@world.std.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: "Roger Orr" <rogero@howzatt.demon.co.uk>
Date: Fri, 27 Feb 2004 15:29:07 CST
Raw View
"Scott Meyers" <Usenet@aristeia.com> wrote in message
news:MPG.1aa86999b63db146989733@news.hevanet.com...
> Classes can declare an operator delete that has the runtime system provide
> the size of the just-destructed-object whose memory is being deallocated:
>
>   void operator delete(void *ptr, size_t sizeOfFormerObject);
>
> Does anybody know why there is no global operator delete with this same
> signature?  A client of mine claims to have a good reason for wanting to
> know the size of the memory being deallocated by the global operator
> delete, and when he asked me why there was no global version like the
class
> version taking a size_t, I found that I had no idea why such a version is
> missing.  Is there a good technical basis for the omission?

I guess the issue is how would the compiler/runtime know which one you
wanted to call?
The standard defines this for the class operator delete in 3.7.3.2p2
[Deallocation functions]:

"If a class T has a member deallocation function named operator
delete with exactly one parameter, then that function is a usual
(nonplacement)
deallocation function. If
class T does not declare such an operator delete but does declare a member
deallocation function
named operator delete with exactly two parameters, the second of which has
type std::size_t
(18.1), then this function is a usual deallocation function."

If you define a class like this:

class DoubleDelete
{
public:
  static void operator delete( void * );
  static void operator delete( void *, size_t );
};

then the operator without the size_t argument will always be called.
In a class you would usually only define the flavour of delete which you
want, this would be problematic at the global level.

Roger Orr
--
MVP in C++ at www.brainbench.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: wade@stoner.com (Bill Wade)
Date: Fri, 27 Feb 2004 17:39:45 CST
Raw View
Scott Meyers <Usenet@aristeia.com> wrote in message news:<MPG.1aa86999b63db146989733@news.hevanet.com>...
> Classes can declare an operator delete that has the runtime system provide
> the size of the just-destructed-object whose memory is being deallocated:
>
>   void operator delete(void *ptr, size_t sizeOfFormerObject);
>
> Does anybody know why there is no global operator delete with this same
> signature?  [...]  Is there a good technical basis for the omission?

The language allows delete to occur at a point where the type is
incomplete (and with separate compilation, the size is not known).
One could argue about whether or not this is a "good" language
feature.  Asking the runtime to remember the size in this case costs
something, even when it isn't needed.

In practice, a user-written global new/delete will frequently be
written in terms of malloc()/free(), and free() does not need to be
"told" the size.

If you want to see see the size at dealloc time, and don't want to use
class::new/delete, you might consider using the std::allocator
interface.  However, it does put more restrictions on the client code.

---
[ 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: Graeme Prentice <invalid@yahoo.co.nz>
Date: Sun, 29 Feb 2004 10:57:45 CST
Raw View
On Fri, 27 Feb 2004 17:39:45 CST, Bill Wade wrote:

>Scott Meyers <Usenet@aristeia.com> wrote in message news:<MPG.1aa86999b63db146989733@news.hevanet.com>...
>> Classes can declare an operator delete that has the runtime system provide
>> the size of the just-destructed-object whose memory is being deallocated:
>>
>>   void operator delete(void *ptr, size_t sizeOfFormerObject);
>>
>> Does anybody know why there is no global operator delete with this same
>> signature?  [...]  Is there a good technical basis for the omission?
>
>The language allows delete to occur at a point where the type is
>incomplete (and with separate compilation, the size is not known).
>One could argue about whether or not this is a "good" language
>feature.  Asking the runtime to remember the size in this case costs
>something, even when it isn't needed.

The type being deleted can be incomplete only if it has a trivial
destructor (i.e. it's not user written and its members and bases all
have trivial destructors) and no deallocation functions (member operator
delete functions).  The runtime wouldn't have to remember the size - if
the class was incomplete, it could call __get_size_for_class_blah_blah
which the compiler provided for all classes with trivial destructors and
the linker removed any that weren't called.  Possibly it wouldn't even
need to call a function - it could just access a constant
__size_of_class_blah_blah that the linker was able to find and "fix up".

Classes with non trivial destructors have to be complete so that the
compiler can actually call the destructor  - even this could probably be
worked around by a call to __destroy_pointer_to_class_blah_blah if the
class was incomplete, but you would have a wasted function call for
incomplete classes with a trivial destructor. (similarly for the member
operator delete situation).


>
>In practice, a user-written global new/delete will frequently be
>written in terms of malloc()/free(), and free() does not need to be
>"told" the size.

If you're writing a memory pool such as the small object allocator in
Loki, the size of the block being deleted is useful.  In Loki's case,
the size value is used to do a binary search through a vector, to find
the specific memory pool for objects of that size.  Blocks of memory
returned by the Loki small object allocator can be as small as one byte
(and there is no additional overhead for that one object) - the size of
an object is never actually stored in dynamic memory anywhere, as it is
with malloc/free.


>
>If you want to see see the size at dealloc time, and don't want to use
>class::new/delete, you might consider using the std::allocator
>interface.  However, it does put more restrictions on the client code.

How would that work?

Suppose we try to write a version of delete that could be called  e.g.
my_delete( some_pointer )  - how would we write my_delete?

template <typename T>
void my_delete( T * ptr )
{
 ptr->T::~T();   // not all compilers like this
      std::cout << "\nmy_delete called. " << sizeof (T);
}

If ptr points to an object derived from T, there's no way to get the
correct size without compiler help or a user written get_size() virtual
function - in which case it's less work to provide the two parameter
operator delete in the base class, and doesn't require remembering to
call my_delete instead of delete.

The language could define that if the user supplied a two parameter
global delete function
void operator delete( void *, size_t );

then calls to delete myptr results in a call to the two parameter
version instead of the one parameter version.  This would save having to
define a two parameter operator delete for all classes.  It's not hard
for the compiler to supply the correct size for polymorphic objects  -
Andrei Alexandrescu suggested four methods of how it can be done in his
book.

Explicit calls to the one parameter global operator delete, as in the
default allocator, would still call the one parameter version, which
would be a problem if the global operator new had been user defined, and
is probably one reason why the global two parameter operator delete
isn't allowed.  Explicit calls to the global one parameter delete could
be made illegal if a two parameter delete was declared though, and as
Josuttis says, writing your own allocator is not hard...   but as Roger
Orr said, this is problematic at the global level   e.g. there could be
explicit calls to the one parameter operator delete from a variety of
places, so it could get messy.  How do you ensure that all memory
allocated from a call to a user written global operator new, gets
deallocated by a call to the corresponding user written global operator
delete  - perhaps the system could guarantee it by forcing all calls to
global delete, to the user written one.

Stroustrup says replacing the global operator new and delete is not for
the fainthearted (15.6 freestore) and points out that other code might
rely on some aspect of the default behaviour or might want to supply
their own version of global new/delete  - i.e. a recipe for conflict.

If I'm wrong, which I could be, it ain't gonna matter.

Graeme

---
[ 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                       ]