Topic: Is `operator new(size_t, void *)' required by draft standard?


Author: kanze@us-es.sel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 05 Dec 1994 17:44:49 GMT
Raw View
In article <3bihrl$mpo@giga.bga.com> jamshid@ses.com (Jamshid Afshar)
writes:

|> In article <KANZE.94Nov30182655@slsvhdt.us-es.sel.de>,
|> James Kanze US/ESC 60/3/141 #40763 <kanze@us-es.sel.de> wrote:

|>  #include <new.h>
|> >|>     void *rawMemory = new char[sizeof SomeClass];
|> >|>     new (rawMemory) SomeClass;

|> Btw, I prefer using `operator new()' directly:

Agreed.  I don't know why, but this didn't occur to me.

|>  void *rawMemory = operator new(sizeof SomeClass);
|>  new (rawMemory) SomeClass;
|>  SomeClass& r = *(SomeClass*)rawMemory;
|>  ...
|>  r.~SomeClass();
|>  operator delete(rawMemory);

|> >The further questions in John's articles were already answered, but I
|> >would like to point out that the above code results in undefined
|> >behavior (although I know of no current implementations for which it
|> >will not work).

|> >Unlike malloc, operator new does *not* guarantee that the memory
|> >returned will be correctly aligned for any data type.  It only
|> >guarantees that the memory will be correctly aligned for the new'ed
|> >type (in this case, char).

|> I've discussed this with Fergus -- see my appended article contianing
|> the WP reference.  Like malloc(), `operator new()' must return a
|> properly aligned block for any type.

I don't have my copy of the WP here to see the exact reference, but
from the section number, I will conclude that it comes from the
library section.

This is relatively new material in the WP, and I'm not sure what it
guarantees in full.  However, note that it is explicitly *not*
guaranteed that the pointer returned by the new operator is the same
as the pointer returned by the function operator new, so there is
still some room for doubt.

|> >C++ also has a function to obtain raw
|> >(uninitialized) memory correctly aligned for any data type.  This
|> >function is called `malloc'.  If you want raw memory, which will later
|> >explicitly be constructed, this is probably the function you should be
|> >using.

|> No, it would be more consistent with the rest of your C++ program and
|> just as safe to use the `operator new()' and `operator delete()'
|> functions instead of malloc() and free().

If the quote you give (from Fergus) is not taken out of context (or
more likely, contradicted elsewhere in the standard), and it remains
so through the final standard, then you are right.

The fact that the committee did add specific words to this effect in
at least one place in the standard is a good indication of intent,
however, and given that I know of no current implementation which
doesn't conform, I don't think that from a practical point of view,
I'd worry too much.

|> >Alternatively, you could allocate something like the
|> >following:
|> >
|> > union X
|> > {
|> >     char                buf[ sizeof SomeClass ] ;
|> >     double              dummyForAlignmentDouble ;
|> >     void*               dummyForAlignmentPointer ;
|> >     long                dummyForAlignmentLong ;
|> > } ;

|> This isn't guaranteed to work.

Which types did I forget?  The rules *do* guarantee that the address
of each of the members of a union is identical to the address of the
union, and that all of the members are correctly aligned.  (Strictly
speaking, I believe that all of the built-in types should be declared.
But from a practical point of view, I cannot conceive of an
architecture on which int had stricter alignment requirements than
long.  Is this what you are referring to?)

|> From: jamshid@ses.com (Jamshid Afshar)
|> Subject: Re: initialization of arrays
|> Message-ID: <CLA1sw.Bor@ses.com>
|> Summary: both default and user-defined `operator new()' return aligned block
|> Date: Tue, 15 Feb 1994 17:55:44 GMT

|> Redirected to comp.std.c++.

|> In article <9404504.26016@mulga.cs.mu.oz.au>,
|> Fergus Henderson <fjh@munta.cs.mu.OZ.AU> wrote:

|> >jamshid@ses.com (Jamshid Afshar) writes:
|> >>Actually, I think you can prove that `new char[...]' must return a
|> >>block of memory properly aligned to store an A.  ANSI C requires
|> >>malloc() to return a block of memory that is properly aligned for any
|> >>object of the requested size or smaller.  [...]

|> >But how do you know that the compiler and the standard library
|> >operator new() aren't cooperating to convey additional information
|> >(such as the exact type requested) via global variables?

|> The "Result semantics" of WP 17.1.1 Free Store requires that "The
|> pointer returned is suitably [aligned] so that it may be assigned to a pointer
|> of any type and then be used to initialize [...] an object or an array
|> of such objects [...]."  The WP also says "Any C++ program that
|> replaces any of [the allocation functions] with functions having
|> different result semantics causes that program to have undefined
|> behavior."

The question is whether this applies to the function operator new, or
to the new operator (in an expression).

As a concrete example: I know of at least one machine where the
hardware requires a double to be aligned on an address multiple of 8,
but requires at most 4 bytes for any other data type (including
pointers).  It also uses 4 byte integers, and has a 32 bit (4 byte)
address space.  Suppose now that the new [] operator always stores the
number of elements allocated at the beginning of the actual memory
obtained from the operator new[] function, and returns a pointer
incremented beyond this position.  Would it be legal for the
implementation to increment 4 bytes whenever the allocated type didn't
contain a double?  (Everything I've heard until now suggests that it
would be.)
--
James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                              -- Beratung in industrieller Datenverarbeitung






Author: kanze@us-es.sel.de (James Kanze US/ESC 60/3/141 #40763)
Date: 30 Nov 1994 17:26:53 GMT
Raw View
In article <3au4lc$98p@seattle.polstra.com> jdp@polstra.com (John
Polstra) writes:

|> In implementing certain kinds of container classes, it is useful to have
|> the following overloaded definition of operator new:

|>     inline void * operator new(size_t, void *p) { return p; }

|> This definition makes it possible to construct an instance of a class on
|> top of a chunk of raw storage, e.g.,

|>     void *rawMemory = new char[sizeof SomeClass];
|>     new (rawMemory) SomeClass;

The further questions in John's articles were already answered, but I
would like to point out that the above code results in undefined
behavior (although I know of no current implementations for which it
will not work).

Unlike malloc, operator new does *not* guarantee that the memory
returned will be correctly aligned for any data type.  It only
guarantees that the memory will be correctly aligned for the new'ed
type (in this case, char).  C++ also has a function to obtain raw
(uninitialized) memory correctly aligned for any data type.  This
function is called `malloc'.  If you want raw memory, which will later
explicitly be constructed, this is probably the function you should be
using.  Alternatively, you could allocate something like the
following:

 union X
 {
     char                buf[ sizeof SomeClass ] ;
     double              dummyForAlignmentDouble ;
     void*               dummyForAlignmentPointer ;
     long                dummyForAlignmentLong ;
 } ;
--
James Kanze         Tel.: (+33) 88 14 49 00        email: kanze@gabi-soft.fr
GABI Software, Sarl., 8 rue des Francs-Bourgeois, F-67000 Strasbourg, France
Conseils en informatique industrielle --
                              -- Beratung in industrieller Datenverarbeitung






Author: jamshid@ses.com (Jamshid Afshar)
Date: 30 Nov 1994 18:55:47 GMT
Raw View
In article <KANZE.94Nov30182655@slsvhdt.us-es.sel.de>,
James Kanze US/ESC 60/3/141 #40763 <kanze@us-es.sel.de> wrote:

 #include <new.h>
>|>     void *rawMemory = new char[sizeof SomeClass];
>|>     new (rawMemory) SomeClass;

Btw, I prefer using `operator new()' directly:

 void *rawMemory = operator new(sizeof SomeClass);
 new (rawMemory) SomeClass;
 SomeClass& r = *(SomeClass*)rawMemory;
 ...
 r.~SomeClass();
 operator delete(rawMemory);

>The further questions in John's articles were already answered, but I
>would like to point out that the above code results in undefined
>behavior (although I know of no current implementations for which it
>will not work).
>
>Unlike malloc, operator new does *not* guarantee that the memory
>returned will be correctly aligned for any data type.  It only
>guarantees that the memory will be correctly aligned for the new'ed
>type (in this case, char).

I've discussed this with Fergus -- see my appended article contianing
the WP reference.  Like malloc(), `operator new()' must return a
properly aligned block for any type.

>C++ also has a function to obtain raw
>(uninitialized) memory correctly aligned for any data type.  This
>function is called `malloc'.  If you want raw memory, which will later
>explicitly be constructed, this is probably the function you should be
>using.

No, it would be more consistent with the rest of your C++ program and
just as safe to use the `operator new()' and `operator delete()'
functions instead of malloc() and free().

>Alternatively, you could allocate something like the
>following:
>
> union X
> {
>     char                buf[ sizeof SomeClass ] ;
>     double              dummyForAlignmentDouble ;
>     void*               dummyForAlignmentPointer ;
>     long                dummyForAlignmentLong ;
> } ;

This isn't guaranteed to work.

Jamshid Afshar
jamshid@ses.com

From: jamshid@ses.com (Jamshid Afshar)
Subject: Re: initialization of arrays
Message-ID: <CLA1sw.Bor@ses.com>
Summary: both default and user-defined `operator new()' return aligned block
Date: Tue, 15 Feb 1994 17:55:44 GMT

Redirected to comp.std.c++.

In article <9404504.26016@mulga.cs.mu.oz.au>,
Fergus Henderson <fjh@munta.cs.mu.OZ.AU> wrote:
>jamshid@ses.com (Jamshid Afshar) writes:
>>Actually, I think you can prove that `new char[...]' must return a
>>block of memory properly aligned to store an A.  ANSI C requires
>>malloc() to return a block of memory that is properly aligned for any
>>object of the requested size or smaller.  [...]
>
>But how do you know that the compiler and the standard library
>operator new() aren't cooperating to convey additional information
>(such as the exact type requested) via global variables?

The "Result semantics" of WP 17.1.1 Free Store requires that "The
pointer returned is suitably [aligned] so that it may be assigned to a pointer
of any type and then be used to initialize [...] an object or an array
of such objects [...]."  The WP also says "Any C++ program that
replaces any of [the allocation functions] with functions having
different result semantics causes that program to have undefined
behavior."

Jamshid Afshar
jamshid@ses.com




Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: Wed, 30 Nov 1994 20:26:10 GMT
Raw View
jdp@polstra.com (John Polstra) writes:

>    inline void * operator new(size_t, void *p) { return p; }
>
>Is this currently a part of the draft standard?
>

Yes.  #include <new.h>.
(I don't think the standard requires that it be inline.)
--
Fergus Henderson - fjh@munta.cs.mu.oz.au




Author: jamshid@ses.com (Jamshid Afshar)
Date: 7 Dec 1994 22:19:45 GMT
Raw View
In article <KANZE.94Dec5184449@slsvhdt.us-es.sel.de>,
James Kanze US/ESC 60/3/141 #40763 <kanze@us-es.sel.de> wrote:
...
James>Alternatively, you could allocate something like the
James>following:
James>
James> union X
James> {
James>     char                buf[ sizeof SomeClass ] ;
James>     double              dummyForAlignmentDouble ;
James>     void*               dummyForAlignmentPointer ;
James>     long                dummyForAlignmentLong ;
James> } ;
>
Jamshid> This isn't guaranteed to work.
>
>Which types did I forget?  The rules *do* guarantee that the address
>of each of the members of a union is identical to the address of the
>union, and that all of the members are correctly aligned.  (Strictly
>speaking, I believe that all of the built-in types should be declared.
>But from a practical point of view, I cannot conceive of an
>architecture on which int had stricter alignment requirements than
>long.  Is this what you are referring to?)

You're right, it is probably possible to prove the above struct (maybe
with a long double, function pointer, and pointer to member? added) is
suitably aligned to store an object of type SomeClass, where SomeClass
can contain anything.  I believe this is true whether it is allocated
or declared in file or function scope.  I just seem to remember from
comp.std.c that this is not strictly guaranteed to work in C, but I
don't know why -- I'll post there.

Jamshid> The "Result semantics" of WP 17.1.1 Free Store requires that "The
Jamshid> pointer returned is suitably [aligned] so that it may be assigned to
Jamshid> a pointer of any type and then be used to initialize [...] an object
Jamshid> or an array of such objects [...]."
>
>The question is whether this applies to the function operator new, or
>to the new operator (in an expression).

You're right -- contrary to what I wrote it is not guaranteed that
`new char[sizeof(SomeClass)]' returns a pointer to a block of memory
suitably aligned to store a SomeClass object.  Calling the function
`operator new(sizeof(SomeClass))' directly is guaranteed to work.  As
would `new X[1]'.

>As a concrete example: I know of at least one machine where the
>hardware requires a double to be aligned on an address multiple of 8,
>but requires at most 4 bytes for any other data type (including
>pointers).  It also uses 4 byte integers, and has a 32 bit (4 byte)
>address space.  Suppose now that the new [] operator always stores the
>number of elements allocated at the beginning of the actual memory
>obtained from the operator new[] function, and returns a pointer
>incremented beyond this position.  Would it be legal for the
>implementation to increment 4 bytes whenever the allocated type didn't
>contain a double?  (Everything I've heard until now suggests that it
>would be.)




Author: jason@cygnus.com (Jason Merrill)
Date: Thu, 24 Nov 1994 07:21:56 GMT
Raw View
>>>>> John Polstra <jdp@polstra.com> writes:

> Bear with me while I give you a little background ...
> In implementing certain kinds of container classes, it is useful to have
> the following overloaded definition of operator new:

>     inline void * operator new(size_t, void *p) { return p; }

> Is this currently a part of the draft standard?

Yes.  It is defined (or at least declared) in the <new> header.

  18.4.1.5  Placement forms                   [lib.new.delete.placement]

1 These  functions  are reserved, a C++ program may not define functions
  that displace the versions in the Standard C++ library.

  18.4.1.5.1  Placement operator new              [lib.placement.op.new]
      void* operator new(size_t size, void* ptr);

1 Returns ptr.

  18.4.1.5.2  Placement operator new[]      [lib.placement.op.new.array]
      void* operator new[](size_t size, void* ptr);

1 Returns ptr.

Jason




Author: jdp@polstra.com (John Polstra)
Date: 22 Nov 1994 17:07:56 -0800
Raw View
Bear with me while I give you a little background ...

In implementing certain kinds of container classes, it is useful to have
the following overloaded definition of operator new:

    inline void * operator new(size_t, void *p) { return p; }

This definition makes it possible to construct an instance of a class on
top of a chunk of raw storage, e.g.,

    void *rawMemory = new char[sizeof SomeClass];
    new (rawMemory) SomeClass;

As far as I can see, a definition like this is almost mandatory for
implementing a vector or array class that can grow dynamically.  (For
what it's worth, HP's implementation of the Standard Template Library
vector class uses this technique.)

Now, here is the problem:  Say I want to use HP's vector class plus another
class from some different library, together in a single module.  And
suppose that the other class also needs and defines this same overloaded
operator new.  I will have two definitions of the same inline function,
and the compiler will report an error.  The two definitions are
identical, but the compiler won't care about that.

In order to avoid this kind of problem, it seems to me that this
common variant of operator new should be required by the standard to
be definined in some standard header file.  That way, any package that
needs it can use it, without worrying about multiple definitions.

Is this currently a part of the draft standard?

If not, could somebody suggest a way to work around the problem I've
described above?

Note, I've already thought of, and rejected, the following ideas:

    * Define SomeClass::operator new(size_t, void *) instead.

      -- I don't own SomeClass.  Anyway, my container is a template
      class, so SomeClass might be a built-in type instead of a
      class.

    * Don't make this overloaded operator new inline.

      -- It will still conflict with the inline version already defined
         in (for example) HP's STL implementation.

--
   John Polstra                                       jdp@polstra.com
   John D. Polstra & Co., Inc.                   Phone (206) 932-6482
   Seattle, Washington USA                         Fax (206) 935-1262
   "Self-knowledge is always bad news."                 -- John Barth