Topic: Memory Allocation


Author: paul.black@vf.vodafone.co.uk
Date: 1996/11/29
Raw View
clamage@taumet.eng.sun.com (Steve Clamage) wrote:
>>paul.black@vf.vodafone.co.uk wrote:
>>I presume that when the requirement that operator new allocates memory
>>suitable for all alignment requirements was added to the standard it
>>was realised that code such as the example specialization in Stroustrup
>>2nd (pg. 177) would be broken.
>>
>>Paul
>
>The requirement is not recent -- it has always been the same -- and that
>example in Stroustrup C++PL2 (if it hasn't been fixed in a later edition)
>is not correct. When you write
> new char[sizeof(something)]
>you get a char array. There is no requirement that it be properly
>aligned for anything but chars.

This is not true as was pointed out by fjh@murlibobo.cs.mu.OZ.AU
(Fergus Henderson) in a previous article:
> |   3.7.3  Dynamic storage duration                    [basic.stc.dynamic]
> |
> | 3 Any allocation and/or deallocation functions defined in a C++  program
> |   shall conform to the semantics specified in this subclause.
> |
> |   3.7.3.1  Allocation functions           [basic.stc.dynamic.allocation]
> [...]
> | 2 The function shall return the address of the start of a block of stor-
> |   age whose length in bytes shall be at least as large as the  requested
> |   size.  [...]  The pointer returned shall  be  suit-
> |   ably  aligned  so that it can be assigned to a pointer of any type and
> |   then used to access the object  or  array  in  the  storage  allocated

If ::new() is used then the Stroustrup example will always work because it is
allocating the same amount of memory as an array of the objects and with
alignment suitable for any types. However, the example code would is not
compliant with the above quoted part of the draft. This is the real issue: Class
specific allocation should only need to worry about class specific issue
(alignment size etc.).

>As a practical matter, most implementations have operator new call
>malloc with the total size of the array, meaning that by accident the
>alignment will be adequate and the code will work.

This is not an accident, ::new will always provide suitable alignment whether
malloc is used or not (see above quoted draft again).

Paul




[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: fjh@mundook.cs.mu.OZ.AU (Fergus Henderson)
Date: 1996/11/30
Raw View
paul.black@vf.vodafone.co.uk writes:

>clamage@taumet.eng.sun.com (Steve Clamage) wrote:
>>When you write
>> new char[sizeof(something)]
>>you get a char array. There is no requirement that it be properly
>>aligned for anything but chars.
>
>This is not true as was pointed out by fjh@murlibobo.cs.mu.OZ.AU
>(Fergus Henderson) in a previous article:

No, I think Steve Clamage is right here.  The text I quoted
from the standard there referred to the `operator new []' function,
not to a `new' expression.  If you wrote

 void * p = operator new [] (sizeof(something));

then you would get memory aligned for anything.  However,
there is no guarantee that `new char [n]' will give you the
same results as `operator new [] (n)'.  The former may allocate
more than `n' bytes of storage (using the `operator new' function)
and may then return a pointer to some non-aligned offset within
the allocated block.

See paragraphs 9 and 12 in [expr.new]:

]   5.3.4  New                                                  [expr.new]
]
] 9 Storage for the object created by a new-expression  is  obtained  from
]   the  appropriate allocation function (_basic.stc.dynamic.allocation_).
]   When the allocation function is called, the first  argument  shall  be
]   the amount of space requested (which shall be no less than the size of
]   the object being created and which may be greater than the size of the
]   object being created only if the object is an array).
]
] 12[Example:
]
]   --new T results in a call of operator new(sizeof(T)),
]
]   --new(2,f) T results in a call of operator new(sizeof(T),2,f),
]
]   --new T[5] results in a call of operator new[](sizeof(T)*5+x), and
]
]   --new(2,f) T[5]       results        in        a        call        of
]     operator new[](sizeof(T)*5+y,2,f).
]
]   Here,  x  and y are non-negative, implementation-defined values repre-
]   senting array allocation overhead.  Their value might  vary  from  one
]   invocation of new to another.  ]

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: clamage@taumet.eng.sun.com (Steve Clamage)
Date: 1996/11/26
Raw View
fjh@mundook.cs.mu.OZ.AU (Fergus Henderson) wrote:
> "Bill Wade" <bill.wade@stoner.com> writes:
[snip]
> >For instance the universally used Hitchhiker IIc has a
> >conforming compiler with the following alignment restrictions:
> >  char: 1
> >  short: 2
> >  int: 4
> >  double: 8
> >  class with vtable (virtual functions): 42
> >So new of any object of 42 bytes or more must be on a boundary of 168,
> >which is the least common multiple of the numbers above.  Naive compiler
> >users might implement their operator new in terms of the 'C' malloc(), as
> >suggested by a footnote in the A95 draft.  However since 'C' doesn't have
> >to deal with vtable pointers, malloc() might be content with 8-byte
> >alignment which is suitable for C, but not C++.
>
> That's not correct.  The malloc() function in a conforming implementation
> must return memory that is suitably aligned for any object, including
> C++ objects.

The only reference I could find to malloc (section 20.4.6) said that malloc was
the same as the standard C library malloc except  malloc (calloc & realloc)
shall not use ::operator new(). I don't have a copy of the standard for C but I
doubt if it has C++ alignment requirements in it.

Having said that, I can't see why classes will have this 42 byte alignment
requirement. The class requirements are (should be) based on the requirements of
the fundamental processor types (which are 2, 4 and 8 bytes). Given the
fundamental types specified, the vtable must only contain chars and shorts
(assuming pointers are the same as ints in terms of size and alignment) or does
the vtable contain fundamental types with 3 or 7 byte alignment requirements?

[more snip]
> >The standard seems to want to make all 'new' functions usable for all 'new'
> >operations.
>
> Yes.  This overconstrains things, IMHO.  (It does make it
> easier to get an efficient implementation of auto_ptr, but
> I don't think that was the original intention, I think the
> wording was just unintentially overconstraining.)

This is what I don't like. I suppose it does allow you to have code like:

    class A { ... };
    class B { ... };
    B * b = new(A::operator new(sizeof(B))) B;

but if you are specializing new() for class A, why should you be required to
think about the alignment for class B?

When B is derived from A then a "new B" may use A::new(). However, if "sizeof(A)
== sizeof(B)" then the alignment is the same, if "sizeof(A) != sizeof(B)" then
::new() would be used to allocate the memory(with suitable alignment).

I presume that when the requirement that operator new allocates memory suitable
for all alignment requirements was added to the standard it was realised that
code such as the example specialization in Stroustrup 2nd (pg. 177) would be
broken.

Paul




[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: clamage@taumet.eng.sun.com (Steve Clamage)
Date: 1996/11/27
Raw View
Due to a glitch in approving the article for moderation, the
following article appeared to be written by me, but it wasn't.
I have a couple of responses to it, and these do indeed come
from me. Sorry for the confusion.
---
Steve Clamage, stephen.clamage@eng.sun.com

>fjh@mundook.cs.mu.OZ.AU (Fergus Henderson) wrote:
>> "Bill Wade" <bill.wade@stoner.com> writes:
>[snip]
>> >For instance the universally used Hitchhiker IIc has a
>> >conforming compiler with the following alignment restrictions:
>> >  char: 1
>> >  short: 2
>> >  int: 4
>> >  double: 8
>> >  class with vtable (virtual functions): 42
>> >So new of any object of 42 bytes or more must be on a boundary of 168,
>> >which is the least common multiple of the numbers above.  Naive compiler
>> >users might implement their operator new in terms of the 'C' malloc(), as
>> >suggested by a footnote in the A95 draft.  However since 'C' doesn't have
>> >to deal with vtable pointers, malloc() might be content with 8-byte
>> >alignment which is suitable for C, but not C++.
>>
>> That's not correct.  The malloc() function in a conforming implementation
>> must return memory that is suitably aligned for any object, including
>> C++ objects.
>
>The only reference I could find to malloc (section 20.4.6) said that
>malloc was the same as the standard C library malloc except  malloc
>(calloc & realloc) shall not use ::operator new(). I don't have a copy
>of the standard for C but I doubt if it has C++ alignment requirements
>in it.

That's just silly. Malloc is required to return a block of memory
suitably aligned for any object of the requested size. That is a
constraint on the C++ implementation, since this is the C++ standard.
Further, malloc is not a user-replaceable function. The C++ implementation
can choose to use somebody's C version of malloc if it wants to, but
if the C++ implementation's alignment requirements are more strict than
the C implementation, the result does not conform to the standard.

>Having said that, I can't see why classes will have this 42 byte alignment
>requirement.

Implementations are allowed to impose whatever alignment requirements
they want. They just have to document the requirements, and ensure that
the implementation-supplied allocation functions have the correct behavior.

For example, some processors have no alignment requirements, but
performance is noticeably improved if certain alignments are used.
Implementations are free to optimize for time (using strict alignment)
or space (using no alignment).

>The class requirements are (should be) based on the requirements of the
>fundamental processor types (which are 2, 4 and 8 bytes). Given the
>fundamental types specified, the vtable must only contain chars and
>shorts (assuming pointers are the same as ints in terms of size and
>alignment) or does the vtable contain fundamental types with 3 or 7
>byte alignment requirements?
>[more snip]
>> >The standard seems to want to make all 'new' functions usable for all
>> >'new' operations.
>>
>> Yes.  This overconstrains things, IMHO.  (It does make it
>> easier to get an efficient implementation of auto_ptr, but
>> I don't think that was the original intention, I think the
>> wording was just unintentially overconstraining.)
>
>This is what I don't like. I suppose it does allow you to have code like:
>
>    class A { ... };
>    class B { ... };
>    B * b = new(A::operator new(sizeof(B))) B;
>
>but if you are specializing new() for class A, why should you be required to
>think about the alignment for class B?
>
>When B is derived from A then a "new B" may use A::new(). However, if
>"sizeof(A) == sizeof(B)" then the alignment is the same, if "sizeof(A)
>!= sizeof(B)" then ::new() would be used to allocate the memory(with
>suitable alignment).
>I presume that when the requirement that operator new allocates memory
>suitable for all alignment requirements was added to the standard it
>was realised that code such as the example specialization in Stroustrup
>2nd (pg. 177) would be broken.
>
>Paul

The requirement is not recent -- it has always been the same -- and that
example in Stroustrup C++PL2 (if it hasn't been fixed in a later edition)
is not correct. When you write
 new char[sizeof(something)]
you get a char array. There is no requirement that it be properly
aligned for anything but chars.

As a practical matter, most implementations have operator new call
malloc with the total size of the array, meaning that by accident the
alignment will be adequate and the code will work.

---
Steve Clamage, stephen.clamage@eng.sun.com
(really, this time)
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]
---
[ 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         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]