Topic: alignment of char[N]


Author: Hans.Olsson@dna.lth.se (Hans Olsson)
Date: 1998/11/10
Raw View
In article <727nio$jm9$1@engnews2.Eng.Sun.COM>,
Steve Clamage <stephen.clamage@sun.com> wrote:
>
>Hans.Olsson@dna.lth.se (Hans Olsson) writes:
>>...
>>>Malloc and free are left over from C. You can use them if you
>>>want, but they don't interact with the C++ type system as do
>>>operator new and operator delete.
>
>>The interaction you refer to must be the fact that operator new/
>>operator delete can be defined on a per-class basis (we are dealing
>>directly with the raw operators here).
>
>Not only that, but you can write, for example,
>       new T
>       new T[n]
>and get
>- properly aligned storage for an object or array of type T with no
>  separate computation of size,
>- automatic object initialization,
>- use of the returned pointer type with no casts.

Of course, but by specifying we are dealing with the raw operators
I tried to make it clear that we for some odd reasons use 'operator new'
directly (e.g. we want to do you own unions as in this thread or
construct variable sized arrays with extra information). This use of
'operator new' has the same problems as if we use 'malloc'.

The standard guarantees that 'malloc', 'operator new' and 'new char[]'
all have approximately the same advantages and dis-advantages
(provided you use matching deallocations and you figure out
how to use the returned memory without violating the standard).

Of course one should wrap it inside another class so that no-one
else has to care about this.

I don't think we need to continue this discussion. The conclusions
are that the final standard guarantees that 'new char[]','operator new'
and 'malloc' can be used to allocate arbitrary chunks of memory
(adding 'new char[]' is an addition from CD2 - I think it's the worst
choice, but it seems as though it is often the first idea tried).
There has also been other changes changes from CD2 in this area, hopefully
one of them was to make Effects under 'operator new' less misleading.



--
// Home page  http://www.dna.lth.se/home/Hans_Olsson/
// Email To..Hans.Olsson@dna.lth.se [Please no junk e-mail]




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Hans.Olsson@dna.lth.se (Hans Olsson)
Date: 1998/11/09
Raw View
In article <71kslm$np$1@engnews1.eng.sun.com>,
Steve Clamage <stephen.clamage@sun.com> wrote:>
>There was an additional reason for the guarantees in 5.3.4,
>paragraph 10 -- appearing in the final standard but not in CD2 --
>which I forgot to mention.
>
>Programmers writing replacement or overloaded versions of operator
>new needed to know that the size requested by a new-expression
>would correspond to the size of the object being allocated.

This is present in CD2 5.3.4 paragraph 9.

...
>Malloc and free are left over from C. You can use them if you
>want, but they don't interact with the C++ type system as do
>operator new and operator delete.

The interaction you refer to must be the fact that operator new/
operator delete can be defined on a per-class basis (we are dealing
directly with the raw operators here).

If this interaction is an advantage is a different issue.

Suppose class T defines its own T::operator new/T::operator delete.
If we use raw operator new/operator delete to allocate objects of type
T we either have to qualify them or ensure that operator new/operator delete
are always(or never) called within member functions of the class (combining
T::operator new and ::operator delete might be lethal).

C's malloc and free does not have these risks, but will OTOH not
use per-class optimized allocators if available.

>I don't know of any implementation that requires extra overhead
>for new char[]. Any operation in C or C++ *might* have some
>overhead in some implementation.

If we compare operator new and and new char[] the standard
makes it explicit that new char[] as default calls 'operator new'
with a possibly larger argument, and both can be used to get
arbitrary chunks of memory (new char[] can also be used to allocate
arrays of chars - which I consider the normal use of new char[],
and see no problems with whatsoever).

That was the overhead I referred to (using 'very' was an unfortunate
choice of words).
Given the choice between two functions where one might use more memory
I prefer the one with less-than-or-equal memory-use, i.e. operator new
(if it has no other dis-advantages).



Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/11/09
Raw View
Hans.Olsson@dna.lth.se (Hans Olsson) writes:
>...
>>Malloc and free are left over from C. You can use them if you
>>want, but they don't interact with the C++ type system as do
>>operator new and operator delete.

>The interaction you refer to must be the fact that operator new/
>operator delete can be defined on a per-class basis (we are dealing
>directly with the raw operators here).

Not only that, but you can write, for example,
 new T
 new T[n]
and get
- properly aligned storage for an object or array of type T with no
  separate computation of size,
- automatic object initialization,
- use of the returned pointer type with no casts.

If you revert to C-style allocation with malloc, you have to compute
the size, call the constructors separately, and use a cast on
the returned pointer. Each of those steps introduces an opportunity
for error and a consequent maintenance burden.

That's what I meant by operator new and delete interacting with
the type system. A new-expression calls the appropriate version
of operator new automatically. You have to write extra code to
make the wrong thing happen.

>If this interaction is an advantage is a different issue.

>Suppose class T defines its own T::operator new/T::operator delete.
>If we use raw operator new/operator delete to allocate objects of type
>T we either have to qualify them or ensure that operator new/operator delete
>are always(or never) called within member functions of the class (combining
>T::operator new and ::operator delete might be lethal).

Why would you ever mix memory-management styles that way? You always
run a risk when you use more than one method to allocate space for
objects of a given type. (How should any given object be deallocated,
if at all?)

The member-specific op new/delete allow you to customize memory
management per class type. Surely part of using a class is knowing
how to allocate it. The class designer has the responsibility of
documenting such things.

Similarly, randomly applying scope qualifiers to function calls is
a bad programming practice, not just in this case. Except in
the special case of implementing a derived-class operation in
terms of a base-class or global operation, needing to use scope
qualifiers is often a sign of poor design. Requiring scope qualifiers
means errors are more likely.

The exception is in templates, where you usually want to qualify
everything, because you can't control the environment where
instantiation might later occur.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Hans.Olsson@dna.lth.se (Hans Olsson)
Date: 1998/11/06
Raw View
In article <71q68o$6hp$1@engnews1.eng.sun.com>,
Steve Clamage <stephen.clamage@sun.com> wrote:
>
>Hans.Olsson@dna.lth.se (Hans Olsson) writes:
>>My question is whether the final standard guarantees this or not.
>>I do not interpret CD2 as guaranteeing this for 'operator new',
>>but only for 'operator new[]'. The standard (but not CD2) ensures
>>that 'new char[]' inherits this property from 'operator new[]'.
>
>Can I please get you to stop referring to CD2? It doesn't matter
>what CD2 says. It only matters what the standard says, and they
>are not the same in this area.

I will stop quoting CD2, as soon as I now what the standard says about
'operator new' (or I buy a version of the standard that allows me to quote
from it).

Your message did contain the information I needed on 'operator new':

>Section 3.7.3.1 on allocation functions has the alignment
>requirement in paragraph 2:
>
>-------------------------------------------
>The allocation function attempts to allocate the requested amount of
>storage. If it is successful, it shall return the address of the
>start of a block of storage whose length in bytes shall be at least
>as large as the requested size. ... The pointer returned shall be
>suitably aligned so that it can be converted to a pointer of any
>complete object type and then used to access the object or array
>in the storage allocated ...
>-------------------------------------------

And therefore 'operator new' must return suitably aligned memory,
and can be used in the trick that started this thread.

However, this alignment restriction was also present in CD2, but I
missed it since 'operator new' explicitly stated that the memory
was aligned for objects of the requested size.

I do not believe that I'm the only one who have misinterpreted the
requirements on 'operator new' (I remember seeing advice about using
malloc for this reason).

I hope that the final standard has a clearer wording so that Effects for
'operator new' does not give a weaker alignment requirement in addition
to the one given for all allocation functions.


--
// Home page  http://www.dna.lth.se/home/Hans_Olsson/
// Email To..Hans.Olsson@dna.lth.se [Please no junk e-mail]




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/11/02
Raw View
Hans.Olsson@dna.lth.se (Hans Olsson) writes:

>In article <71cvom$hfv$1@engnews1.eng.sun.com>,
>Steve Clamage <clamage@Eng.Sun.COM> wrote:
>>Hans.Olsson@dna.lth.se (Hans Olsson) writes:
>>>I see no reason for adding such a requirement that late in the
>>>standarization process (since operator new/malloc existed).
>>>BTW: Why was signed char excluded?
>>
>>The problem was that the original wording did not provide the
>>right guarantees about size and alignment for the result of
>>new-expressions. I don't know why signed char was excluded.

There was an additional reason for the guarantees in 5.3.4,
paragraph 10 -- appearing in the final standard but not in CD2 --
which I forgot to mention.

Programmers writing replacement or overloaded versions of operator
new needed to know that the size requested by a new-expression
would correspond to the size of the object being allocated. For
example, a common idiom for a class-specific operator-new is this:
 if( size == sizeof(*this) ) {
  ... get an object from local free list
 }
 else {
  ... get the space from global operator new;
 }
If you are not assured that the size requested by the new-
expression matches the size of the object being allocated, this
idiom won't work -- the test won't succeed, and you never use
the local free list designed to speed up memory recycling.

>At least excluding signed char is consistent with the definition of POD
>types (3.9/2), but I still fail to understand why we need
>operator new, malloc, and now also new char[] and new unsigned char[]
>that can all be used to do the same thing.

Malloc and free are left over from C. You can use them if you
want, but they don't interact with the C++ type system as do
operator new and operator delete.

"Operator new" is a function. "new char[]" is a new-expression, a
syntactic language construct that, among other things, calls some
version of an "operator new" function. The two are different
categories of things and serve different (but related) purposes.

A new-expression gets an object or array of a specified type.
Do you advocate making it impossible to get an array of
unsigned chars?

>The possible overhead of array allocation for new char[] makes
>it very unattractive.

I don't know of any implementation that requires extra overhead
for new char[]. Any operation in C or C++ *might* have some
overhead in some implementation. If this operation has overhead,
it is probably because the implemention provides some checking
for you.  If so, the implementation probably also provides a way
for you to turn off the checking.

>[deleted]

>This is not the what it say in CD2.

It doesn't matter what it says in CD2. The details of dynamic
memory management are different in the final standard, as I have
said several times. Continuing to quote CD2 is a waste of time.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Email_To::.Hans.Olsson@dna.lth.se (Hans Olsson)
Date: 1998/11/02
Raw View
In article <71cvom$hfv$1@engnews1.eng.sun.com>,
Steve Clamage <clamage@Eng.Sun.COM> wrote:
>Hans.Olsson@dna.lth.se (Hans Olsson) writes:
>>I see no reason for adding such a requirement that late in the
>>standarization process (since operator new/malloc existed).
>>BTW: Why was signed char excluded?
>
>The problem was that the original wording did not provide the
>right guarantees about size and alignment for the result of
>new-expressions. I don't know why signed char was excluded.

At least excluding signed char is consistent with the definition of POD
types (3.9/2), but I still fail to understand why we need
operator new, malloc, and now also new char[] and new unsigned char[]
that can all be used to do the same thing.

The possible overhead of array allocation for new char[] makes
it very unattractive.

[deleted]
>Allocation functions (such as operator new or operator new[]) are
>unconditionally constrained to return storage properly aligned for
>any object that could be stored in the requested memory. Your
>operator new[] above does not meet this requirement.

This is not the what it say in CD2.

In CD2 the memory is suitable for all objects of the _given_ size, whereas
in your statement you state that it suitable for all objects that
fit in the given size (i.e. of size not larger than the given size).

The question is thus: what is size?

Is the result of sizeof (as I assume) or is it the actual
size of the object not including alignment restrictions (as you assume)?

If size refers to the result of sizeof I can't find any violations of
the standard in my example, and the intent is clearly to allow it.
Since the program will not work properly I find that somewhat disturbing.

The wording of sizeof in CD2 (5.3.3/2) seems to assume that the size is the
size as returned by sizeof, i.e. supporting my interpretation.

Of course all of this might also have changed between CD2 and the
final standard.

--
// Home page  http://www.dna.lth.se/home/Hans_Olsson/
// Email To..Hans.Olsson@dna.lth.se [Please no junk e-mail]




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/11/03
Raw View
Hans.Olsson@dna.lth.se (Hans Olsson) writes:

>I now remembered one additional problem:

>operator new should return memory suitably aligned for objects of
>any type that will fit in the requested size (18.4.1.1 in CD2).

>What does _size_ mean? Is it the size as returned by sizeof or
>the actual size of the object without taking alignment into account?

"Size" means the size requested in the argument to operator new.
That is, every version of operator new must have a first parameter
that is the number of bytes requested. The operator new returns
a pointer to at least that much storage, aligned suitably for
ANY object that can fit in the requested number of bytes.

There is no concept of "the actual size of the object" distinct
from "sizeof" in C or C++. If you try to create an object of type
X in fewer than sizeof(X) bytes, the results are undefined.

You can ask operator new for more than sizeof(X) bytes if you
want. The resulting storeage might be more strictly aligned than
if you requested only sizeof(X), but it cannot be less strictly
aligned. (I hope the reason is obvious.)

>How about malloc?

The alignment constraints on malloc and operator new are the same.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/11/03
Raw View
Christian Bau wrote:
 >
 > For example: You have an architecture with a natural word size of
 > eight bytes, but short is two bytes only. In this architecture, there
 > are efficent instructions to read/write a short if its location in its
 > eight byte word is known, but it is much more difficult to read/write
 > it if that is unknown.
 >
 > Given a struct like
 >
 >    typedef struct mystruct { short a; short b; short c; short d; }
 >
 > the compiler would decide that mystruct has an alignment of eight, so
 > if you have a pointer
 >
 >    mystruct* p;
 >
 > the element p->a can be accessed with one efficient instruction, lets
 > say called "load first 16 bit". If you then set p to a pointer that is
 > incorrectly aligned, this instruction would not trap, but silently
 > load the wrong data!

My point is that such a machine will undoubtedly also have at least one
built-in type, either long, long double, or void*, that also requires
eight-byte alignment.

--

Ciao,
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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/11/04
Raw View
Hans.Olsson@dna.lth.se (Hans Olsson) writes:

>In article <71cvom$hfv$1@engnews1.eng.sun.com>,
>Steve Clamage <clamage@Eng.Sun.COM> wrote:
>...
>>The problem was that the original wording did not provide the
>>right guarantees about size and alignment for the result of
>>new-expressions.

>My question is whether the final standard guarantees this or not.
>I do not interpret CD2 as guaranteeing this for 'operator new',
>but only for 'operator new[]'. The standard (but not CD2) ensures
>that 'new char[]' inherits this property from 'operator new[]'.

Can I please get you to stop referring to CD2? It doesn't matter
what CD2 says. It only matters what the standard says, and they
are not the same in this area. Here is 5.3.4 paragraph 10:

-------------------------------------------
A new-expression passes the amount of space requested to the
allocation function as the first argument of type std::size_t. That
argument shall be no less than the size of the object being created;
it may be greater than the size of the object being created only if
the object is an array. For arrays of char and unsigned char, the
difference between the result of the new-expression and the address
returned by the allocation function shall be an integral multiple
of the most stringent alignment requirement (3.9) of any object
type whose size is no greater than the size of the array being
created. [ Note: Because allocation functions are assumed to return
pointers to storage that is appropriately aligned for objects of
any type, this constraint on array allocation overhead permits the
common idiom of allocating character arrays into which objects of
other types will later be placed. ]
-------------------------------------------

Notice the guarantee that a new-expression for a single object
must pass exactly the size of the object being created to the
allocation function.

Section 3.7.3.1 on allocation functions has the alignment
requirement in paragraph 2:

-------------------------------------------
The allocation function attempts to allocate the requested amount of
storage. If it is successful, it shall return the address of the
start of a block of storage whose length in bytes shall be at least
as large as the requested size. ... The pointer returned shall be
suitably aligned so that it can be converted to a pointer of any
complete object type and then used to access the object or array
in the storage allocated ...
-------------------------------------------


>Since sizeof gives the size including alignment restrictions it seems
>logical that 'operator new' can assume that the size includes alignment,
>and thus return a pointer suitable for objects of exactly that size,
>which e.g. means that an objects of size 15 need not be 4-byte aligned.

No, the alignment requirement says "any object". You can request
15 bytes and store a smaller object in it.  If any object that has
a size no greater than 15 bytes has an 8-byte alignment requirement,
the allocation function must return storage aligned on an 8-byte
boundary.

An allocation function can be called directly; no new-expression
need be involved.  An allocation function can therefore make no
assumptions whatever about the types that are involved or the uses
to which the storage will be put.  It must make the most
pessimistic assumptions about alignment, and that is what 3.7.3.1
says explicitly.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Hans.Olsson@dna.lth.se (Hans Olsson)
Date: 1998/11/04
Raw View
In article <71cvom$hfv$1@engnews1.eng.sun.com>,
Steve Clamage <clamage@Eng.Sun.COM> wrote:
...
>The problem was that the original wording did not provide the
>right guarantees about size and alignment for the result of
>new-expressions.

My question is whether the final standard guarantees this or not.
I do not interpret CD2 as guaranteeing this for 'operator new',
but only for 'operator new[]'. The standard (but not CD2) ensures
that 'new char[]' inherits this property from 'operator new[]'.

[deleted]
>Allocation functions (such as operator new or operator new[]) are
>unconditionally constrained to return storage properly aligned for
>any object that could be stored in the requested memory. Your
>operator new[] above does not meet this requirement.

My program (incorrectly) used 'operator new' instead of 'operator new[]'.

You are right that 'operator new[]' does have this requirement, but
'operator new' does not have it (at least not in CD2):

----
18.4.1.1 void *operator new(std::size_t size) throw(bad_alloc);
Effects:
 The allocation function called by a new-expression to allocate size
 bytes of storage  suitably aligned to represent any object of that size.
----

Note that this does not say any object that could be stored in the
requested memory or that could fit in the requested but any object
of _that_ _size_. For 'operator new[]' this is made explicit:

18.4.1.2 void* operator new[](std::size_t size) throw(bad_alloc);
---
Effects:
    The allocation function called  by the array form  of a new-expression
    to allocate size bytes of storage suitably aligned to represent any
    array object of that size OR SMALLER. (Emphasis added).
---
The size is not explicitly defined in CD2, but does in general
refer to the result of sizeof applied to an object.

Since sizeof gives the size including alignment restrictions it seems
logical that 'operator new' can assume that the size includes alignment,
and thus return a pointer suitable for objects of exactly that size,
which e.g. means that an objects of size 15 need not be 4-byte aligned.

Some quotes from CD2 supporting that size is the result of sizeof:
---
3.9/4 Types:
  The  object representation of an object of type T is the sequence of N
  unsigned char objects taken up by the object of type T, where N equals
  sizeof(T).   The  value representation of an object is the set of bits
  that hold the value of type T.  For POD types, the  value  representa-
  tion  is  a set of bits in the object representation that determines a
  value, which is one discrete element of an implementation-defined  set
  of values.

5.3.3/2 sizeof:
  When applied to a reference or a reference type,  the  result  is  the
  size  of  the referenced type.  When applied to a class, the result is
  the number of bytes in an object of that class including  any  padding
  required  for placing objects of that type in an array.  ...
  When applied to an array, the result is the  total number  of bytes
  in the array.  This implies that the size of an array
  of n elements is n times the size of an element.
---
All of this might have changed between CD2 and the final standard;
or my interpretation might be incorrect.

I would hope that this is the case, but I would like to have it
confirmed.

BTW: The default behaviour of 'operator new[]' is to call 'operator new'!
--
// Home page  http://www.dna.lth.se/home/Hans_Olsson/
// Email To..Hans.Olsson@dna.lth.se [Please no junk e-mail]



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1998/11/06
Raw View
Hans Olsson wrote:
>
> In article <71cvom$hfv$1@engnews1.eng.sun.com>,
> Steve Clamage <clamage@Eng.Sun.COM> wrote:
....
> >Allocation functions (such as operator new or operator new[]) are
> >unconditionally constrained to return storage properly aligned for
> >any object that could be stored in the requested memory. Your
> >operator new[] above does not meet this requirement.
>
> This is not the what it say in CD2.
>
> In CD2 the memory is suitable for all objects of the _given_ size, whereas
> in your statement you state that it suitable for all objects that
> fit in the given size (i.e. of size not larger than the given size).

The C++ standard says in section 3.7.3.1, about allocation functions,
that "The pointer returned shall be suitably aligned so that it can be
converted to a pointer of any complete object type ant then used to
access the object or array in the storage allocated ...". The size
doesn't come into it; it's entirely an issue of alignment.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1998/10/29
Raw View
Gabriel Netterdag wrote:
>
> Steve Clamage wrote:
...
> > OTOH, if you allocate raw storage with malloc or operator new, you
                                                              ^^^
> > are assured that the storage will be aligned suitably for any
                                 ^^^^^^^^^^^^^^^^^^^^^^^^
> > object that can be contained in the space. (If you write your
> > own operator new, that is one of its constraints.)
>
> So how about:
> char * p = new char[sizeof(T)];
             ^^^
> If this will not give you proper alignment for any object,
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ?
> I really don't understand what 5.3.4/10 means.

Re-read the last paragraph of his message.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Ross Smith" <ross.s@ihug.co.nz>
Date: 1998/10/29
Raw View
Francis Glassborow wrote in message <9TMYujALd6N2EwO1@robinton.demon.co.uk>...
>
>In article <7180de$hme$1@newsource.ihug.co.nz>, Ross Smith
><ross.s@ihug.co.nz> writes
>>
>>Sorry, CD2 is the best most of us can do. Not everyone has access to
>>a copy of the final standard.
>
>Well why not spoil yourself and spend a miserly $18? That is all it
>takes to be up-to-date.

Only if you're (1) American, (2) have a credit card, (3) have enough
patience to slowly trial-and-error your way through ANSI's unspeakable
registration form, and (4) are willing to trust your money to an
organisation that can't get something as trivial as a web page right.
I score 0 out of 4.

--
Ross Smith ................................... mailto:ross.s@ihug.co.nz
.............. The Internet Group, Auckland, New Zealand ..............
                               * * * * *
      "Screw up your courage. You've screwed up everything else."




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: herbs@cntc.com (Herb Sutter)
Date: 1998/10/29
Raw View
On 27 Oct 1998 22:16:37 GMT, sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
wrote:
>What is the alignment of char[N].  I want to be able to put any
>object in this uninitialized space.

Short answer: Don't. See my column in the July/August 1998 C++ Report,
with the sidebar entitled "Reckless Fixes and Optimizations, and Why
They're Evil." :)

Herb


---
Herb Sutter (mailto:herbs@cntc.com)

Current Network Technologies Corp  2695 North Sheridan Way, Suite 150
www.cntc.com www.peerdirect.com    Mississauga Ontario Canada L5K 2N6


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Gabriel Netterdag <ecagane@sgens.ericsson.se>
Date: 1998/10/29
Raw View

David R Tribble wrote:

> >     char * p = new char[sizeof(T)];
>
> As James points out, this will work, since '::operator new()' should
> always return a pointer to a memory area that is suitably aligned for
> any object type; this is due to the simple reason that ::new has no
> knowledge about the type of the object that is being constructed, so
> it must assume a worst-case alignment.

Yes, true, allocation functions must return storage that
is aligned for objects of any type.
But this doesn't mean that, for example, new short[N] or
new int[N] will be suitable alignment for any object.

5.3.4/10 say that:
"for arrays of char and unsigned char, the difference between
the result of the new-expression and the address returned by
the allocation function shall be an integral multiple of the
most stringent alignment requirement......."


> >     char  place[sizeof(Something)];
> >     Something *  p = new(place) Something();
>
> This is a different situation, since operator new isn't involved.
> Here we're attempting to construct an object on top of an area
> that was originally defined as an auto char array.  The problem
> with this, as James alluded to, is that an auto char array only
> has char alignment; there's no guarantee that it will be properly
> aligned for any other object type.  (I think, therefore, that the
> example in 18.4.3.1 is in error.)

(I did, of course, mention the wrong section. it should read: 18.4.1.3/4)

I would have to agree. I can't find anything that puts
some kind of requirement on char arrays with auto/static storage.
If this is the case, 18.4.1.3/4 is somewhat misleading.

Regards
//Gabriel




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Gabriel Netterdag <ecagane@sgens.ericsson.se>
Date: 1998/10/29
Raw View

James Kuyper wrote:

> Gabriel Netterdag wrote:
> >
> > Steve Clamage wrote:
> ...
> > > OTOH, if you allocate raw storage with malloc or operator new, you
>                                                               ^^^
> > > are assured that the storage will be aligned suitably for any
>                                  ^^^^^^^^^^^^^^^^^^^^^^^^
> > > object that can be contained in the space. (If you write your
> > > own operator new, that is one of its constraints.)
> >
> > So how about:
> > char * p = new char[sizeof(T)];
>              ^^^
> > If this will not give you proper alignment for any object,
>           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ?
> > I really don't understand what 5.3.4/10 means.
>
> Re-read the last paragraph of his message.

What did I miss?
Steve wrote 'operator new', I asked about the new-expression.
IMHO two different beasts. My understanding is when you
allocate arrays with new T[N], the address returned from
the allocator (operator new) might not be the same as the
result from the expression-new. This makes it possible to
allocate extra "internal" storage for array length, etc.

Steve mentioned malloc and operator new as required to
return storage aligned for any object, but as he didn't
say anything about char new[N] required to do the same,
I asked if I have failed to understand 5.3.4/10
It states that for char/unsigned char arrays, the difference
between the result of a new-expression and the address
returned from the allocation function shall be an integral
multiple of the most stringent alignment requirement.

Regards
//Gabriel




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: blargg@flash.net (Gargantua Blargg)
Date: 1998/10/29
Raw View
In article <9TMYujALd6N2EwO1@robinton.demon.co.uk>, Francis Glassborow
<francisG@robinton.demon.co.uk> wrote:

> In article <7180de$hme$1@newsource.ihug.co.nz>, Ross Smith
> <ross.s@ihug.co.nz> writes
> >
> >Sorry, CD2 is the best most of us can do. Not everyone has access to
                     ^^^^
> >a copy of the final standard.
>
> Well why not spoil yourself and spend a miserly $18? That is all it
> takes to be up-to-date.

Oh, they have a nice HTML version of the final standard now? Note Ross
said the "best" most of us can do. I don't think many would consider a
read-only (no text copying allowed, even to quote parts of the standard!)
version of the final standard better than the HTML format of CD2.

I would gladly put down $18 if it got me an HTML version like CD2.

--
blarggflash.net | Gargantua Blargg | http://www.flash.net/~blargg/


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/10/30
Raw View
Gabriel Netterdag wrote:
>
> Steve mentioned malloc and operator new as required to
> return storage aligned for any object, but as he didn't
> say anything about char new[N] required to do the same,
> I asked if I have failed to understand 5.3.4/10
> It states that for char/unsigned char arrays, the difference
> between the result of a new-expression and the address
> returned from the allocation function shall be an integral
> multiple of the most stringent alignment requirement.

You're quite right. It goes on to explain that the purpose of this
clause is to support "the common idiom of allocating character arrays
into which objects of other types will later be placed."

--

Ciao,
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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/10/30
Raw View
Christopher Eltschka wrote:
>
> The problem with this is that you never know if you have all
> possibilities for all existing compilers.
> What if the next compiler aligns structs on 16 byte boundaries,
> but all built-in types only at a max alignment of 4?

I'm trying to imagine why on earth a compiler would align a structure
more strictly than any of its components. And even if it did that for
some obscure efficiency reason, I can't imagine a CPU that would
actually trap if a structure actually turned out to have only the
four-byte alignment.

--

Ciao,
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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/11/02
Raw View
Hans.Olsson@dna.lth.se (Hans Olsson) writes:

>In article <3638AB65.9FF85785@sgens.ericsson.se>,
>Gabriel Netterdag  <ecagane@sgens.ericsson.se> wrote:
>>
>>Yes, true, allocation functions must return storage that
>>is aligned for objects of any type.
>>But this doesn't mean that, for example, new short[N] or
>>new int[N] will be suitable alignment for any object.
>>
>>5.3.4/10 say that:
>>"for arrays of char and unsigned char, the difference between
>>the result of the new-expression and the address returned by
>>the allocation function shall be an integral multiple of the
>>most stringent alignment requirement......."

>This is not present in CD2; can you confirm that it was added to
>the final standard?

Details of dynamic memory management were tweaked for the final
standard, and some paragraphs were moved around.  Some words that
were accidently dropped between CD1 and CD2 were restored.

>I see no reason for adding such a requirement that late in the
>standarization process (since operator new/malloc existed).
>BTW: Why was signed char excluded?

The problem was that the original wording did not provide the
right guarantees about size and alignment for the result of
new-expressions. I don't know why signed char was excluded.

>Furthermore, the statement does not guarantee anything by itself,
>unless there are requirements on the argument to the allocation function
>not present in CD2.

>As an example, consider the following (assuming strictest alignment is 8):

>void *operator new(size_t x) {
>  if (x%8) return memory aligned on 4-byte boundaries
>  ...
>};
>char*new char[](size_t x) {return 8+(char*)(operator new(x+12));}

>double *x=(double*)(new char[sizeof(double)]); // Oops not 8-byte aligned.

>Does the standard make this version of new char[] illegal?

You are mixing up requirements on what the compiler generates for
a new-expression (the paragraph quoted above, 5.3.4/10), and
requirements on allocation functions.

Recall that a new-expression results in a call on an allocation
function, followed by construction of objects. The compiler might
generate other bookkeeping code as well. For example, if an
array-delete expression does not have compile-time access to the
number of elements allocated, that information must be stored
someplace at run time by the array-new expression.

The quoted paragraph recognizes that the compiler might want to
request some extra space beyond what is needed for the array
being allocated. If so, the compiler-generated code must preserve
alignment.

Allocation functions (such as operator new or operator new[]) are
unconditionally constrained to return storage properly aligned for
any object that could be stored in the requested memory. Your
operator new[] above does not meet this requirement.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Gabriel Netterdag <netterdag@hotmail.com>
Date: 1998/11/02
Raw View
Paul D. DeRocco wrote:
>
> You're quite right. It goes on to explain that the purpose of this
> clause is to support "the common idiom of allocating character arrays
> into which objects of other types will later be placed."
>
As I understand it, there is still a small difference
between malloc/operator new and new char/unsigned char[N].

For new char/unsigned char[N], the difference between new and the result
from the allocator shall be an integral multiple of the most stringent
alignment requirement of any object type
*whose size is no greater then the size of the array being created*.
As I see it, the result will not necessarily be the *most* stringent,
but it's safe to put any object type that will fit into the array.
This will make it possible not to "waste" storage, if the only
object types that will fit in the storage have less alignment then
the *most* stringent alignment requirement.
But still, you wouldn't put a larger object in the array
then the size of the array anyway.

Regards
//Gabriel
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Email_To::.Hans.Olsson@dna.lth.se (Hans Olsson)
Date: 1998/11/02
Raw View
In article <3637B31F.24B4@noSPAM.central.beasys.com>,
David R Tribble  <dtribble@technologist.com> wrote:
>As James points out, this will work, since '::operator new()' should
>always return a pointer to a memory area that is suitably aligned for
>any object type; this is due to the simple reason that ::new has no
>knowledge about the type of the object that is being constructed, so
>it must assume a worst-case alignment.

I now remembered one additional problem:

operator new should return memory suitably aligned for objects of
any type that will fit in the requested size (18.4.1.1 in CD2).

What does _size_ mean? Is it the size as returned by sizeof or
the actual size of the object without taking alignment into account?

Assume we use the trick in this thread for the following situation:

template <class T> struct X {
 int size;
 T ptr[1];
};

X<char> *x=(X<char> *)operator new(sizeof(X)+sizeof(char)*3);

Must operator new return memory suitably aligned for int even in this
situation?

How about malloc? (I vaguely remember that malloc might be superior
under these circumstances, but I'm not sure if this was based
on reading the standard or some pre-standard problem).




--
// Home page  http://www.dna.lth.se/home/Hans_Olsson/
// Email To..Hans.Olsson@dna.lth.se [Please no junk e-mail]
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: christian.bau@isltd.insignia.com (Christian Bau)
Date: 1998/11/02
Raw View
In article <36395163.162CACEB@ix.netcom.com>, "Paul D. DeRocco"
<pderocco@ix.netcom.com> wrote:

> Christopher Eltschka wrote:
> >
> > The problem with this is that you never know if you have all
> > possibilities for all existing compilers.
> > What if the next compiler aligns structs on 16 byte boundaries,
> > but all built-in types only at a max alignment of 4?
>
> I'm trying to imagine why on earth a compiler would align a structure
> more strictly than any of its components. And even if it did that for
> some obscure efficiency reason, I can't imagine a CPU that would
> actually trap if a structure actually turned out to have only the
> four-byte alignment.

For example: You have an architecture with a natural word size of eight
bytes, but short is two bytes only. In this architecture, there are
efficent instructions to read/write a short if its location in its eight
byte word is known, but it is much more difficult to read/write it if that
is unknown.

Given a struct like

   typedef struct mystruct { short a; short b; short c; short d; }

the compiler would decide that mystruct has an alignment of eight, so if
you have a pointer

   mystruct* p;

the element p->a can be accessed with one efficient instruction, lets say
called "load first 16 bit". If you then set p to a pointer that is
incorrectly aligned, this instruction would not trap, but silently load
the wrong data!

(Does anyone know how close Alpha comes to this description? )
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1998/10/28
Raw View
Nate Lewis wrote:
>
> Steve Clamage wrote in message <715ipu$o21$1@engnews1.eng.sun.com>...
> >OTOH, if you allocate raw storage with malloc or operator new, you
> >are assured that the storage will be aligned suitably for any
> >object that can be contained in the space. (If you write your
> >own operator new, that is one of its constraints.)
>
> >sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:
> >>class Silly
> >>{
> >>     private:
> >>          char d_object[Max<sizeof(A),sizeof(B)>::VAL];
> >>};
>
> Though I couldn't find it in the standard, doesn't the same hold true of
> auto or static storage?  Seems to me like it ought to.  If so, then the

No. The difference between dynamic storage and the other two types is
that the actual object it will be used for is not known by the allocator
at the time it is allocated. Therefore, the memory must be suitably
aligned for an arbitrary object. Static and automatic memory need only
be suitably aligned for the particular object type the memory is
allocated to.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Paul D. DeRocco" <pderocco@ix.netcom.com>
Date: 1998/10/28
Raw View
Siemel Naran wrote:
>
> What is the alignment of char[N].  I want to be able to put any
> object in this uninitialized space.  Is the following code
> portable?  It does work on egcs 1.1b and como 4.2.38 in Linux.
>
> class Silly
> {
>      private:
>           enum { isA, isB } d_which;
>           char d_object[Max<sizeof(A),sizeof(B)>::VAL];
>           A& asA() { return reinterpret_cast<A&>(d_object); }
>           B& asB() { return reinterpret_cast<B&>(d_object); }
>
>      public:
>           Silly(const A& a) : d_which(isA) { new (&asA()) A(a); }
>           Silly(const B& b) : d_which(isB) { new (&asB()) B(b); }
>
>           ~Silly()
>           {
>                switch (d_which)
>                {
>                     case isA: asA().~A(); break;
>                     case isB: asB().~B(); break;
>                }
>           }
> };

With some compiler switches, that won't work with Borland, because it
will allocate one byte for d_which, and then allocate d_object at the
following byte, and the entire structure will have no reason to be
anything stronger than byte-aligned. I'd try this:

 class Silly {
 private:
     enum { isA, isB } d_which;
     union {
         char junk1[sizeof(A)];
         char junk2[sizeof(B)];
         long junk3;
         long double junk4;
         void* junk5;
         } d_object;
     ...
 };

The union lets you eliminate the Max template, and also combine it with
other items that force stronger alignment. (I'm of the opinion that it
is never necessary to use more than a long, a long double, and a plain
pointer for this purpose, but others disagree.)

One might be tempted to put the enum last, in the hope that if it's a
byte, it will save some space, but alignment requirements also force
padding at the end of objects, not just in the middle, so that arrays
will work correctly. Thus, there is no advantage to rearranging the
items.

--

Ciao,
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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Email_To::.Hans.Olsson@dna.lth.se (Hans Olsson)
Date: 1998/10/28
Raw View
In article <715ipu$o21$1@engnews1.eng.sun.com>,
Steve Clamage <stephen.clamage@sun.com> wrote:
..
>Some CPUs have no alignment restrictions, although performance
>improves when objects are suitably aligned. Intel's x86 chips
>have that property, for example, and your code would work.
>
>Other CPU's have important alignment requirements. For example,
>type double has an 8-byte alignment requirement on some CPUs.
>If class A contains a double, and the alignment of d_which is
>4 bytes, on average half the A subobjects will be misaligned,
>and would cause a program abort when referenced.

To make it more accurate (and also more complex) you should say that
some instructions on some CPU have important alignment requirements.

E.g. the some(all?) sparc CPU have instructions to load/store
8-byte aligned double, but also (slower) instructions to load/store
4-byte aligned doubles.

Different compilers might align doubles as 4-byte or 8-byte, and issue
load/store for 4 or 8-byte aligned doubles.

Thus switching compilers might detect incorrectly aligned doubles
(I've seen it happen), and calling C/Fortran routines from
your C++-code might require you to have stricter alignment than for
the doubles used in the C++-code.

You should thus always ensure that the malloc and operator new return
memory suited for the strictest alignment on the CPU - even if your
compiler does not use this alignment.
(Stack based objects are a special problem).
--
// Home page  http://www.dna.lth.se/home/Hans_Olsson/
// Email To..Hans.Olsson@dna.lth.se [Please no junk e-mail]
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Gabriel Netterdag <ecagane@sgens.ericsson.se>
Date: 1998/10/28
Raw View
Steve Clamage wrote:

> The alignment of an array of objects does not need to be any
> more stringent than the alignment of its element type. You are
> therefore not assured (by the C++ standard) that a variable or
> class member of type array-of-char will have any special alignment.
> (The alignment of a char is 1 by definition.)
>
> An implementation is allowed to use stricter alignment.
>
> OTOH, if you allocate raw storage with malloc or operator new, you
> are assured that the storage will be aligned suitably for any
> object that can be contained in the space. (If you write your
> own operator new, that is one of its constraints.)

So how about:
char * p = new char[sizeof(T)];

If this will not give you proper alignment for any object,
I really don't understand what 5.3.4/10 means.
I has a note saying:
"Because allocation functions are assumed to to return pointers
to storage that is appropriately aligned for objects of any type,
this constraint on array allocation overhead permits the common
idiom of allocating character arrays into which objects of other
types will later be placed."

18.4.1.3 show an example of a placement new on
an array of char:

char place[sizeof(Something)]
Something* p = new (place) Something();

So what you say above, this isn't good thing to do?

Regards
//Gabriel
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/10/28
Raw View
Gargantua Blargg wrote:
 >
 > In article <715ipu$o21$1@engnews1.eng.sun.com>, stephen.clamage@sun.com
 > (Steve Clamage) wrote:
 >
 > > sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:
 > > >
 > ...
 > > >Is the following code
 > > >portable?  It does work on egcs 1.1b and como 4.2.38 in Linux.
 > >
 > > >class Silly
 > > >{
 > > >     private:
 > > >          enum { isA, isB } d_which;
 > > >          char d_object[Max<sizeof(A),sizeof(B)>::VAL];
 > > >          A& asA() { return reinterpret_cast<A&>(d_object); }
 > > >          B& asB() { return reinterpret_cast<B&>(d_object); }
 > > >
 > > >     public:
 > > >          Silly(const A& a) : d_which(isA) { new (&asA()) A(a); }
 > > >          Silly(const B& b) : d_which(isB) { new (&asB()) B(b); }
 > >
 > > >          ~Silly()
 > > >          {
 > > >               switch (d_which)
 > > >               {
 > > >                    case isA: asA().~A(); break;
 > > >                    case isB: asB().~B(); break;
 > > >               }
 > > >          }
 > > >};
 > ...
 > > If neither A nor B has a non-trivial default constructor, you
 > > can create a union, which will be properly aligned.
 > >         class Silly {
 > >                 ...
 > >                 union { // anonymous union
 > >                         A a; // access as 'a' member of Silly
 > >                         B b; // access as 'b' member of Silly
 > >                 };
 > >                 ...
 > >         };
 > > Unfortunately, no object, not even a simple value object, that
 > > has a user-written default constructor can be placed in a union.
 > >
 > > If you make d_object a pointer and put the storage on the heap,
 > > the A and B objects will always be properly aligned.
 >
 > OK, so why did you leave out the Word solution (See Stroustrup C++
 > Programming Language, 2nd edition, page 466)?
 >
 > union Word {
 >     char c;
 >     int i;
 >     long l;
 >     float f;
 >     double d;
 >     long double ld;
 >     void* p;
 >     void (Word::*mf)();
 >     void (*fp)();
 >     // add whatever else here
 > };
 >
 > union
 > {
 >     char bytes_needed [n];
 >     Word align_this_thing;
 > } data;
 >
 > Since Word required the most strict alignment for any type, this forces
 > the union data to be aligned most strictly, so the bytes_needed array is
 > aligned properly.

The problem with this is that you never know if you have all
possibilities for all existing compilers.
What if the next compiler aligns structs on 16 byte boundaries,
but all built-in types only at a max alignment of 4?

I (still) think there should be a standard type "align"
with this property, used for exactly this purpose (and to get
the max. alignment with sizeof(align)).


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/10/28
Raw View
Siemel Naran wrote:

> What is the alignment of char[N].

Good question

> I want to be able to put any
> object in this uninitialized space.  Is the following code
> portable?

No

> class Silly

You mean class union, don't you ?

> {
>      private:
>           enum { isA, isB } d_which;
>           char d_object[Max<sizeof(A),sizeof(B)>::VAL];

I have just implemented the same thing, written allmost the same
way (same MM<X,Y>::max stuff, same enum) three days ago !

To ensure correct alignement, I use:

union {
    char c[size];
    align_type<T> c;
};

Since all unions members have the same address, this ensure that
the alignement of align_type<T> is applied to c. I have implemented
align_type:

http://pages.pratique.fr/~bonnardv/source/color/STLAlignement.h.html

Formally this is undefined but I expect it to work on all common
architectures (it assumes that the alignement for any type is no
larger than the alignement for fondamental integrals, floating
points, and pointer types).

Of course, I would prefer to have an align_type from the
standard.

Allocating raw data inside the object is a usefull time and
space optimisation. Also it makes sens with the clean conceptual
C++ model which separates allocation and construction.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/10/28
Raw View
"Ross Smith" <ross.s@ihug.co.nz> writes:

>Steve Clamage wrote in message <715ipu$o21$1@engnews1.eng.sun.com>...
>>
>>OTOH, if you allocate raw storage with malloc or operator new, you
>>are assured that the storage will be aligned suitably for any
>>object that can be contained in the space.

>I know that's true for malloc, but is it true for new?

>CD2 5.3.4 [expr.new]:

Don't refer to CD2 any more. Use the final standard. There
are differences.

Besides, notice that I said "operator new," not "a new-expression".

The section you want is 3.7.3.1 "Allocation functions".

The section on new-expression refers to operator new, and
the sections on operator new refer to 3.7.3.1.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 1998/10/28
Raw View
Paul D. DeRocco wrote:
 >
 > Siemel Naran wrote:
 >
 > > What is the alignment of char[N].  I want to be able to put any
 > > object in this uninitialized space.  Is the following code
 > > portable?  It does work on egcs 1.1b and como 4.2.38 in Linux.
 > >
 > > class Silly
 > > {
 > >      private:
 > >           enum { isA, isB } d_which;
 > >           char d_object[Max<sizeof(A),sizeof(B)>::VAL];
 > >           A& asA() { return reinterpret_cast<A&>(d_object); }
 > >           B& asB() { return reinterpret_cast<B&>(d_object); }
 > >
 > >      public:
 > >           Silly(const A& a) : d_which(isA) { new (&asA()) A(a); }
 > >           Silly(const B& b) : d_which(isB) { new (&asB()) B(b); }
 > >
 > >           ~Silly()
 > >           {
 > >                switch (d_which)
 > >                {
 > >                     case isA: asA().~A(); break;
 > >                     case isB: asB().~B(); break;
 > >                }
 > >           }
 > > };
 >
 > With some compiler switches, that won't work with Borland, because it
 > will allocate one byte for d_which, and then allocate d_object at the
 > following byte, and the entire structure will have no reason to be
 > anything stronger than byte-aligned. I'd try this:
 >
 >         class Silly {
 >         private:
 >             enum { isA, isB } d_which;
 >             union {
 >                 char junk1[sizeof(A)];
 >                 char junk2[sizeof(B)];
 >                 long junk3;
 >                 long double junk4;
 >                 void* junk5;
 >                 } d_object;
 >             ...
 >         };
 >
 > The union lets you eliminate the Max template, and also combine it with
 > other items that force stronger alignment. (I'm of the opinion that it
 > is never necessary to use more than a long, a long double, and a plain
 > pointer for this purpose, but others disagree.)

And they do so correctly. There is no finite list of types that is
guaranteed to include the most strictly aligned type for an arbitrary
implementation. As a practical matter, implementation may have
implementation-specific types as extensions, such as 'long long', which
could have stricter alignment requirements than any standard type. Your
version of the Silly class could not be implemented for such a type.

I was going to say 'instantiated', when I noticed that Silly isn't a
template class. Surely it was intended to be one?



[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Ross Smith" <ross.s@ihug.co.nz>
Date: 1998/10/28
Raw View
Steve Clamage wrote in message <717mrg$kbs$1@engnews1.eng.sun.com>...
>
>"Ross Smith" <ross.s@ihug.co.nz> writes:
>
>>Steve Clamage wrote in message <715ipu$o21$1@engnews1.eng.sun.com>...
>>>
>>>OTOH, if you allocate raw storage with malloc or operator new, you
>>>are assured that the storage will be aligned suitably for any
>>>object that can be contained in the space.

>>I know that's true for malloc, but is it true for new?

>>CD2 5.3.4 [expr.new]:

>Don't refer to CD2 any more. Use the final standard. There
>are differences.

Sorry, CD2 is the best most of us can do. Not everyone has access to
a copy of the final standard.

>Besides, notice that I said "operator new," not "a new-expression".

>The section you want is 3.7.3.1 "Allocation functions".

>The section on new-expression refers to operator new, and
>the sections on operator new refer to 3.7.3.1.

Ah, thanks. I didn't know it was possible to call these underlying
functions directly.

--
Ross Smith ................................... mailto:ross.s@ihug.co.nz
.............. The Internet Group, Auckland, New Zealand ..............
                               * * * * *
      "Screw up your courage. You've screwed up everything else."




[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: David R Tribble <david.tribble@noSPAM.central.beasys.com>
Date: 1998/10/29
Raw View
Steve Clamage wrote:
>> The alignment of an array of objects does not need to be any
>> more stringent than the alignment of its element type. You are
>> therefore not assured (by the C++ standard) that a variable or
>> class member of type array-of-char will have any special alignment.
>> (The alignment of a char is 1 by definition.)
>> An implementation is allowed to use stricter alignment.
>>
>> OTOH, if you allocate raw storage with malloc or operator new, you
>> are assured that the storage will be aligned suitably for any
>> object that can be contained in the space. (If you write your
>> own operator new, that is one of its constraints.)

James Kuyper <kuyper@wizard.net> wrote:
> The difference between dynamic storage and the other two types is
> that the actual object it will be used for is not known by the
> allocator at the time it is allocated. Therefore, the memory must be
> suitably aligned for an arbitrary object. Static and automatic memory
> need only be suitably aligned for the particular object type the
> memory is allocated to.

Gabriel Netterdag wrote:
> So how about:
>     char * p = new char[sizeof(T)];

As James points out, this will work, since '::operator new()' should
always return a pointer to a memory area that is suitably aligned for
any object type; this is due to the simple reason that ::new has no
knowledge about the type of the object that is being constructed, so
it must assume a worst-case alignment.

> If this will not give you proper alignment for any object,
> I really don't understand what 5.3.4/10 means.
> I has a note saying:
>  "Because allocation functions are assumed to to return pointers
>  to storage that is appropriately aligned for objects of any type,
>  this constraint on array allocation overhead permits the common
>  idiom of allocating character arrays into which objects of other
>  types will later be placed."

Yes, this will always work (unless the behavior of ::new has been
changed).

> 18.4.1.3 show an example of a placement new on an array of char:
>     char  place[sizeof(Something)];
>     Something *  p = new(place) Something();
>
> So what you say above, this isn't good thing to do?

This is a different situation, since operator new isn't involved.
Here we're attempting to construct an object on top of an area
that was originally defined as an auto char array.  The problem
with this, as James alluded to, is that an auto char array only
has char alignment; there's no guarantee that it will be properly
aligned for any other object type.  (I think, therefore, that the
example in 18.4.3.1 is in error.)

-- David R. Tribble, dtribble@technologist.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1998/10/29
Raw View
In article <7180de$hme$1@newsource.ihug.co.nz>, Ross Smith
<ross.s@ihug.co.nz> writes
>
>Sorry, CD2 is the best most of us can do. Not everyone has access to
>a copy of the final standard.

Well why not spoil yourself and spend a miserly $18? That is all it
takes to be up-to-date.

Francis Glassborow      Chair of Association of C & C++ Users
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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1998/10/29
Raw View
"Nate Lewis" <nlewis@mindspring.com> writes:

>Steve Clamage wrote in message <715ipu$o21$1@engnews1.eng.sun.com>...
>>OTOH, if you allocate raw storage with malloc or operator new, you
>>are assured that the storage will be aligned suitably for any
>>object that can be contained in the space. (If you write your
>>own operator new, that is one of its constraints.)

>>sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:
>>>class Silly
>>>{
>>>     private:
>>>          char d_object[Max<sizeof(A),sizeof(B)>::VAL];
>>>};

>Though I couldn't find it in the standard, doesn't the same hold true of
>auto or static storage?  Seems to me like it ought to.

Yes, but not in the way you mean. Any complete object has
alignment requirements, and the compiler when allocating
an object of that type must assure the alignment requirements
are met. There is no special rule to cover that case, but
the general rule is that a program that has defined behavior
must exhibit that behavior when compiled and run. Taking
care of object alignment falls under that rule.

In the code above, class Silly is defined to contain
a char array, but not any A or B object, so there is no
assurance that Silly will be properly aligned for an A or a B.

In comparison, a general allocation function (global operator new
or malloc) gets no type information, and so must return storage
aligned suitably for any object that might later be constructed
in it.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: James Kuyper <kuyper@wizard.net>
Date: 1998/10/29
Raw View
Ross Smith wrote:
...
> Sorry, CD2 is the best most of us can do. Not everyone has access to
> a copy of the final standard.

It only costs $18, and you can pick it up over the internet. The
relevant URL should be in the FAQ somewhere.
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1998/10/27
Raw View
What is the alignment of char[N].  I want to be able to put any
object in this uninitialized space.  Is the following code
portable?  It does work on egcs 1.1b and como 4.2.38 in Linux.

class Silly
{
     private:
          enum { isA, isB } d_which;
          char d_object[Max<sizeof(A),sizeof(B)>::VAL];
          A& asA() { return reinterpret_cast<A&>(d_object); }
          B& asB() { return reinterpret_cast<B&>(d_object); }

     public:
          Silly(const A& a) : d_which(isA) { new (&asA()) A(a); }
          Silly(const B& b) : d_which(isB) { new (&asB()) B(b); }

          ~Silly()
          {
               switch (d_which)
               {
                    case isA: asA().~A(); break;
                    case isB: asB().~B(); break;
               }
          }
};

--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.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    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1998/10/27
Raw View
sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:


>What is the alignment of char[N].  I want to be able to put any
>object in this uninitialized space.

The alignment of an array of objects does not need to be any
more stringent than the alignment of its element type. You are
therefore not assured (by the C++ standard) that a variable or
class member of type array-of-char will have any special alignment.
(The alignment of a char is 1 by definition.)

An implementation is allowed to use stricter alignment.

OTOH, if you allocate raw storage with malloc or operator new, you
are assured that the storage will be aligned suitably for any
object that can be contained in the space. (If you write your
own operator new, that is one of its constraints.)

>Is the following code
>portable?  It does work on egcs 1.1b and como 4.2.38 in Linux.

>class Silly
>{
>     private:
>          enum { isA, isB } d_which;
>          char d_object[Max<sizeof(A),sizeof(B)>::VAL];
>          A& asA() { return reinterpret_cast<A&>(d_object); }
>          B& asB() { return reinterpret_cast<B&>(d_object); }
>
>     public:
>          Silly(const A& a) : d_which(isA) { new (&asA()) A(a); }
>          Silly(const B& b) : d_which(isB) { new (&asB()) B(b); }

>          ~Silly()
>          {
>               switch (d_which)
>               {
>                    case isA: asA().~A(); break;
>                    case isB: asB().~B(); break;
>               }
>          }
>};

On what platforms, and for what kind of classes A and B, does
it work? (Rhetorical question.)

Some CPUs have no alignment restrictions, although performance
improves when objects are suitably aligned. Intel's x86 chips
have that property, for example, and your code would work.

Other CPU's have important alignment requirements. For example,
type double has an 8-byte alignment requirement on some CPUs.
If class A contains a double, and the alignment of d_which is
4 bytes, on average half the A subobjects will be misaligned,
and would cause a program abort when referenced.

If neither A nor B has a non-trivial default constructor, you
can create a union, which will be properly aligned.
 class Silly {
  ...
  union { // anonymous union
   A a; // access as 'a' member of Silly
   B b; // access as 'b' member of Silly
  };
  ...
 };
Unfortunately, no object, not even a simple value object, that
has a user-written default constructor can be placed in a union.

If you make d_object a pointer and put the storage on the heap,
the A and B objects will always be properly aligned.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Nate Lewis" <nlewis@mindspring.com>
Date: 1998/10/28
Raw View
Steve Clamage wrote in message <715ipu$o21$1@engnews1.eng.sun.com>...
>OTOH, if you allocate raw storage with malloc or operator new, you
>are assured that the storage will be aligned suitably for any
>object that can be contained in the space. (If you write your
>own operator new, that is one of its constraints.)

>sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:
>>class Silly
>>{
>>     private:
>>          char d_object[Max<sizeof(A),sizeof(B)>::VAL];
>>};


Though I couldn't find it in the standard, doesn't the same hold true of
auto or static storage?  Seems to me like it ought to.  If so, then the
above would be defined, since Silly's storage itself will be suitably
aligned for an A or a B, and d_object comes first.  Right?  I would
expect the presence of a vptr to break this on 8-byte-aligned machines,
but shouldn't the class above work portably (even though a raw character
buffer may not)?

Does this all fall down because object layout is not specified?  I'm
guessing (sorry) that it does, if there are other variables with less
stringent alignment requirements (like that type enum) present in the
class; PODs can't have padding before the first member, I believe, but
does that hold for non-PODs?

More questions than answers here, I suppose :)

--
Nate Lewis, MCSD
nlewis@mindspring.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Ross Smith" <ross.s@ihug.co.nz>
Date: 1998/10/28
Raw View
Steve Clamage wrote in message <715ipu$o21$1@engnews1.eng.sun.com>...
>
>OTOH, if you allocate raw storage with malloc or operator new, you
>are assured that the storage will be aligned suitably for any
>object that can be contained in the space.

I know that's true for malloc, but is it true for new?

CD2 5.3.4 [expr.new]:

13The allocation function shall either return null or  a  pointer  to  a
  block  of  storage  in  which  space  for  the  object shall have been
  reserved.  [Note: the block of storage is assumed to be  appropriately
  aligned  and  of the requested size. The address of the created object
  will not necessarily be the same as that of the block if the object is
  an array.  ]

I read that to mean that the storage returned by new is only required
to be suitably aligned for the specified type, not for any type.

--
Ross Smith ................................... mailto:ross.s@ihug.co.nz
.............. The Internet Group, Auckland, New Zealand ..............
                               * * * * *
      "Screw up your courage. You've screwed up everything else."
---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: blargg@flash.net (Gargantua Blargg)
Date: 1998/10/28
Raw View
In article <715ipu$o21$1@engnews1.eng.sun.com>, stephen.clamage@sun.com
(Steve Clamage) wrote:

> sbnaran@fermi.ceg.uiuc.edu (Siemel Naran) writes:
> >
...
> >Is the following code
> >portable?  It does work on egcs 1.1b and como 4.2.38 in Linux.
>
> >class Silly
> >{
> >     private:
> >          enum { isA, isB } d_which;
> >          char d_object[Max<sizeof(A),sizeof(B)>::VAL];
> >          A& asA() { return reinterpret_cast<A&>(d_object); }
> >          B& asB() { return reinterpret_cast<B&>(d_object); }
> >
> >     public:
> >          Silly(const A& a) : d_which(isA) { new (&asA()) A(a); }
> >          Silly(const B& b) : d_which(isB) { new (&asB()) B(b); }
>
> >          ~Silly()
> >          {
> >               switch (d_which)
> >               {
> >                    case isA: asA().~A(); break;
> >                    case isB: asB().~B(); break;
> >               }
> >          }
> >};
...
> If neither A nor B has a non-trivial default constructor, you
> can create a union, which will be properly aligned.
>         class Silly {
>                 ...
>                 union { // anonymous union
>                         A a; // access as 'a' member of Silly
>                         B b; // access as 'b' member of Silly
>                 };
>                 ...
>         };
> Unfortunately, no object, not even a simple value object, that
> has a user-written default constructor can be placed in a union.
>
> If you make d_object a pointer and put the storage on the heap,
> the A and B objects will always be properly aligned.

OK, so why did you leave out the Word solution (See Stroustrup C++
Programming Language, 2nd edition, page 466)?

union Word {
    char c;
    int i;
    long l;
    float f;
    double d;
    long double ld;
    void* p;
    void (Word::*mf)();
    void (*fp)();
    // add whatever else here
};

union
{
    char bytes_needed [n];
    Word align_this_thing;
} data;

Since Word required the most strict alignment for any type, this forces
the union data to be aligned most strictly, so the bytes_needed array is
aligned properly.

--
blarggflash.net | Gargantua Blargg | http://www.flash.net/~blargg/


[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]