Topic: What is the purpose of TR1's aligned_storage?
Author: "Peter Dimov" <pdimov@gmail.com>
Date: Fri, 8 Jul 2005 12:33:04 CST Raw View
Me wrote:
> template<class T>
> struct delay {
> aligned_storage<sizeof(T), alignment_of<T>::value> data;
>
> T & get() { return *static_cast<T*>(static_cast<void*>(&data)); }
>
> // we can define a bunch of inits when we get perfect forwarding,
> // this is just a simplified example
> void ctor()
> {
> new (&data) T();
> }
>
> void dtor()
> {
> get().~T();
> }
> };
>
> delay<T> t;
> .
> t.ctor();
> some_operation(t.get());
> t.dtor();
>
> This instantiation of of aligned_storage must somehow magically contain
> any arbitrary T as one of its members (and not construct it), otherwise
> there are no legal ways this can work in terms of 3.10/15.
The relevant clause is 3.8/1. The construction of t obtains storage
with proper size and alignment for T. t.ctor() completes the
constructor call. The lifetime of the object t.get() begins. After
t.ctor() completes, and before t.dtor() is called, the dynamic type of
t.get() is T (access is safe because of 3.10/15, first bullet).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Me" <anti_spam_email2003@yahoo.com>
Date: Fri, 8 Jul 2005 18:18:56 CST Raw View
Peter Dimov wrote:
> The relevant clause is 3.8/1. The construction of t obtains storage
> with proper size and alignment for T. t.ctor() completes the
> constructor call. The lifetime of the object t.get() begins. After
> t.ctor() completes, and before t.dtor() is called, the dynamic type of
> t.get() is T (access is safe because of 3.10/15, first bullet).
I have a more detailed description of the problem I'm drafting, but I
will just mention this for now as to show you why I think we are
disagreeing here.
1.8/1:
- An object is a region of storage
- An object has a type (3.9)
- The term object type refers to the type with which the object is
created[*]
3.10/15:
If a program attempts to access the stored value of an object through
an lvalue of other than one of the following types the behavior is
undefined
Take a look at [*]. C99 (and the one that I agree with because it
"feels" more correct to me) takes the view that the type of the object
is the *declared* type and uses the "effective type" wording to deal
with special cases like allocated objects and unions[^]. You seem to be
taking the view that the type of the object is the *constructed* type.
Taking the view of the constructed type has more problems (IMHO) than
the effective type wording because object lifetimes are involved and
throwing PODs into the mix makes this even more difficult to specify.
But for now, lets deal with something more simpler/relevant to the
legality of aligned_storage:
Assume that unsigned long and unsigned int have the same representation
on this implementation (I can't seem to find a paragraph in the C++
standard that says on this implementation that pointers to unsigned
long and pointers to unsigned int can be casted to eachother so I will
just say that assume that these pointers can be. Anybody want to reply
with what paragraph of the standard allows this pointer conversion (or
the one that would happen with aligned_storage) to be defined by the
standard?):
#define P(T,x) (*(T*)(void*)&(x))
typedef unsigned long ulong;
typedef unsigned int uint;
ulong u;
P(uint,u) = 10;
What happens? Why?
ulong u;
new (&u) uint(5);
What happens? Why?
ulong u;
u.~ulong();
new (&u) uint;
P(uint,u) = 10;
What happens? Why?
// variation of above example but with correct
// ctor/dtor sequence, just so you don't have
// to worry that PODs are involved
ulong u;
u.~ulong();
new (&u) uint;
P(uint,u) = 10;
uint a = P(uint,u);
P(uint,u).~uint();
new (&u) ulong;
What happens? Why?
void *p = operator new(sizeof(ulong));
*(ulong*)p = 10;
*(uint*)p += *(uint*)p;
operator delete(p);
What happens? Why?
[^] Not exactly. C99 is missing the "active union member" wording that
the C++ standard has and there was an attempt to merge the wording but
as of the C99 TC2 draft I have, it seems to be missing. I believe it's
because it was too hard to specify correctly. For more information
about this see (watch for wrapping):
http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_236.htm
search for "alias" and continue reading from that point:
http://www.open-std.org/JTC1/SC22/WG14/www/docs/n973.txt
http://www.open-std.org/JTC1/SC22/WG14/www/docs/n987.txt
Also, I want to clarify what I said earlier in this thread as there
seems to be a common misconception. The aliasing rules aren't symmetric
(especially with respect to char/unsigned char)!!! For example, on a
platform where unsigned int and unsigned char have the same
representation (and pointers to such objects):
unsigned char x;
P(unsigned, x) = 10;
is undefined by the aliasing rules
unsigned x;
P(unsigned char, x) = 10;
must assign 10 to c.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Peter Dimov" <pdimov@gmail.com>
Date: 9 Jul 2005 14:30:14 GMT Raw View
Me wrote:
> Peter Dimov wrote:
> > The relevant clause is 3.8/1. The construction of t obtains storage
> > with proper size and alignment for T. t.ctor() completes the
> > constructor call. The lifetime of the object t.get() begins. After
> > t.ctor() completes, and before t.dtor() is called, the dynamic type of
> > t.get() is T (access is safe because of 3.10/15, first bullet).
>
> I have a more detailed description of the problem I'm drafting, but I
> will just mention this for now as to show you why I think we are
> disagreeing here.
>
> 1.8/1:
> - An object is a region of storage
> - An object has a type (3.9)
> - The term object type refers to the type with which the object is
> created[*]
>
> 3.10/15:
> If a program attempts to access the stored value of an object through
> an lvalue of other than one of the following types the behavior is
> undefined
>
> Take a look at [*]. C99 (and the one that I agree with because it
> "feels" more correct to me) takes the view that the type of the object
> is the *declared* type and uses the "effective type" wording to deal
> with special cases like allocated objects and unions[^]. You seem to be
> taking the view that the type of the object is the *constructed* type.
I think that this is the view taken by the C++ standard. Frankly, I'm
not interested in what C99 says.
> Taking the view of the constructed type has more problems (IMHO) than
> the effective type wording because object lifetimes are involved and
> throwing PODs into the mix makes this even more difficult to specify.
I'm not sure that the facts match your claim, given the problems with
the C99 approach, but that's irrelevant.
> But for now, lets deal with something more simpler/relevant to the
> legality of aligned_storage:
>
> Assume that unsigned long and unsigned int have the same representation
> on this implementation (I can't seem to find a paragraph in the C++
> standard that says on this implementation that pointers to unsigned
> long and pointers to unsigned int can be casted to eachother so I will
> just say that assume that these pointers can be. Anybody want to reply
> with what paragraph of the standard allows this pointer conversion (or
> the one that would happen with aligned_storage) to be defined by the
> standard?):
>
> #define P(T,x) (*(T*)(void*)&(x))
> typedef unsigned long ulong;
> typedef unsigned int uint;
>
> ulong u;
> P(uint,u) = 10;
>
> What happens? Why?
&u contains an object of type uint with value 10. If you access u as
ulong, the behavior is undefined. If you access it as an uint, the
stored value is 10.
> ulong u;
> new (&u) uint(5);
>
> What happens? Why?
Same as above, except that the stored value is 5.
> ulong u;
> u.~ulong();
> new (&u) uint;
> P(uint,u) = 10;
>
> What happens? Why?
Same as above, 10.
> // variation of above example but with correct
> // ctor/dtor sequence, just so you don't have
> // to worry that PODs are involved
> ulong u;
> u.~ulong();
> new (&u) uint;
> P(uint,u) = 10;
> uint a = P(uint,u);
> P(uint,u).~uint();
> new (&u) ulong;
>
> What happens? Why?
Same as above, except that after 'new (&u) ulong' the uint may no
longer be accessed (neither can the uninitialized ulong, though.)
> void *p = operator new(sizeof(ulong));
> *(ulong*)p = 10;
> *(uint*)p += *(uint*)p;
Undefined behavior because of the two uint accesses.
[...]
> unsigned char x;
> P(unsigned, x) = 10;
>
> is undefined by the aliasing rules
No, it isn't. The aliasing rules don't even come into play in this
example, because no stored value is being accessed.
unsigned v = P(unsigned, x);
would be undefined.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Me" <anti_spam_email2003@yahoo.com>
Date: 6 Jul 2005 20:10:04 GMT Raw View
> You're missing three points. One, the point of the TR1 is to add new
> stuff to the standard. If the standard says it's OK, it's OK even
> when other more general wording would suggest it's undefined behavior.
> This applies doubly so when sample implementations are shown.
The TR1 draft copy that I have doesn't suggest anything about what
aligned_storage can be used for, which is why the title of this thread
is worded that way and why I'm asking what are the legal uses of it.
With more compilers that are stricter about aliasing, this information
is important to know.
> Secondly, aliasing rules don't apply here. Every object could be
> accessed via an unsigned char*, and __data has that type.
They do apply here. It's true that you can access a type T via unsigned
char, but it's not the case that you can access an unsigned char (or an
array of them) via a type T. For example, lets take one of the probable
uses for aligned_storage (which I'm assuming is intended to work),
delayed construction:
template<class T>
struct delay {
aligned_storage<sizeof(T), alignment_of<T>::value> data;
T & get() { return *static_cast<T*>(static_cast<void*>(&data)); }
// we can define a bunch of inits when we get perfect forwarding,
// this is just a simplified example
void ctor()
{
new (&data) T();
}
void dtor()
{
get().~T();
}
};
delay<T> t;
.
t.ctor();
some_operation(t.get());
t.dtor();
This instantiation of of aligned_storage must somehow magically contain
any arbitrary T as one of its members (and not construct it), otherwise
there are no legal ways this can work in terms of 3.10/15.
> Finally, the standard describes many works of magic. Aliaser is no
> more magic then e.g. type_info or operator new. That magic is of course
> a lot easier if you know the target. On a platform without alignment,
> it's *really* easy.
I thought TR1 was a pure library proposal. You can see this in the
temporary provisions for the type traits that allow compilers some
leeway.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dave@boost-consulting.com (David Abrahams)
Date: Thu, 7 Jul 2005 05:17:29 GMT Raw View
"Me" <anti_spam_email2003@yahoo.com> writes:
> This instantiation of of aligned_storage must somehow magically
> contain any arbitrary T as one of its members (and not construct
> it), otherwise there are no legal ways this can work in terms of
> 3.10/15.
Let's see:
If a program attempts to access the stored value of an object
through an lvalue of other than one of the fol- lowing types the
behavior is undefined 48):
--- the dynamic type of the object,
--- a cv-qualified version of the dynamic type of the object,
--- a type that is the signed or unsigned type corresponding to the
dynamic type of the object,
--- a type that is the signed or unsigned type corresponding to a
cv-qualified version of the dynamic type of the object,
--- an aggregate or union type that includes one of the
aforementioned types among its members (including, recursively,
a member of a subaggregate or contained union),
--- a type that is a (possibly cv-qualified) base class type of the
dynamic type of the object,
--- a char or unsigned char type.
I think you're overloooking that an lvalue of type T can come from a
char array. Otherwise, malloc, operator new, std::vector, and just
about every other use of dynamic memory in C++ would be invalid. All
you have to do is static_cast a void* to a T* and dereference it.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Me" <anti_spam_email2003@yahoo.com>
Date: 7 Jul 2005 06:40:05 GMT Raw View
> > Secondly, aliasing rules don't apply here. Every object could be
> > accessed via an unsigned char*, and __data has that type.
>
> They do apply here. It's true that you can access a type T via unsigned
> char, but it's not the case that you can access an unsigned char (or an
> array of them) via a type T. For example, lets take one of the probable
> uses for aligned_storage (which I'm assuming is intended to work),
> delayed construction:
>
> template<class T>
> struct delay {
> aligned_storage<sizeof(T), alignment_of<T>::value> data;
>
> T & get() { return *static_cast<T*>(static_cast<void*>(&data)); }
>
> // we can define a bunch of inits when we get perfect forwarding,
> // this is just a simplified example
> void ctor()
> {
> new (&data) T();
> }
>
> void dtor()
> {
> get().~T();
> }
> };
>
> delay<T> t;
> .
> t.ctor();
> some_operation(t.get());
> t.dtor();
>
> This instantiation of of aligned_storage must somehow magically contain
> any arbitrary T as one of its members (and not construct it), otherwise
> there are no legal ways this can work in terms of 3.10/15.
Actually, I even botched this part. Even if aligned_storage magically
contains T, this still isn't legal. You can access T from an
aggregate/union containing T, but not the other way around. So as it
stands, aligned_storage is of very limited use given the current
aliasing rules. So unless the aliasing rules get changed somehow, I
don't think aligned_storage should be in the standard as it encourages
undefined code.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "msalters" <Michiel.Salters@logicacmg.com>
Date: Thu, 7 Jul 2005 10:26:47 CST Raw View
Me schreef:
> It's true that you can access a type T via unsigned
> char, but it's not the case that you can access an unsigned char (or an
> array of them) via a type T.
Actually, that's not the point. The lifetime of an unsigned char[]
ends when a T is constructed in the memory formerly taken by that
array.
> For example, lets take one of the probable
> uses for aligned_storage (which I'm assuming is intended to work),
> delayed construction:
>
> template<class T>
> struct delay {
> aligned_storage<sizeof(T), alignment_of<T>::value> data;
>
> T & get() { return *static_cast<T*>(static_cast<void*>(&data)); }
>
> // we can define a bunch of inits when we get perfect forwarding,
> // this is just a simplified example
> void ctor()
> {
> new (&data) T();
> }
>
> void dtor()
> {
> get().~T();
> }
> };
>
> delay<T> t;
> .
> t.ctor();
> some_operation(t.get());
> t.dtor();
>
> This instantiation of of aligned_storage must somehow magically contain
> any arbitrary T as one of its members (and not construct it), otherwise
> there are no legal ways this can work in terms of 3.10/15.
Nope. aligned_storage<T> doesn't contain a T as one of it's
members, but the memory occupied by aligned_storage<T> is suitable
to constuct a T in.
> > Finally, the standard describes many works of magic. Aliaser is no
> > more magic then e.g. type_info or operator new. That magic is of course
> > a lot easier if you know the target. On a platform without alignment,
> > it's *really* easy.
>
> I thought TR1 was a pure library proposal. You can see this in the
> temporary provisions for the type traits that allow compilers some
> leeway.
There's pure and pure. In particular, there are features that could
be implemented in a pure, portable library. Other features can be
implemented in coomon standard library implementations, without
changing the "core compiler" but still require non-portable constructs.
E.g. even CHAR_MAX is an example from the last category. You just
have to match the core compiler, not change it. Alignment is similar.
Regards,
Michiel Salters
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Me" <anti_spam_email2003@yahoo.com>
Date: Thu, 7 Jul 2005 13:13:09 CST Raw View
David Abrahams wrote:
> "Me" <anti_spam_email2003@yahoo.com> writes:
>
> > This instantiation of of aligned_storage must somehow magically
> > contain any arbitrary T as one of its members (and not construct
> > it), otherwise there are no legal ways this can work in terms of
> > 3.10/15.
>
> Let's see:
>
> If a program attempts to access the stored value of an object
> through an lvalue of other than one of the fol- lowing types the
> behavior is undefined 48):
>
> --- the dynamic type of the object,
>
> --- a cv-qualified version of the dynamic type of the object,
>
> --- a type that is the signed or unsigned type corresponding to the
> dynamic type of the object,
>
> --- a type that is the signed or unsigned type corresponding to a
> cv-qualified version of the dynamic type of the object,
>
> --- an aggregate or union type that includes one of the
> aforementioned types among its members (including, recursively,
> a member of a subaggregate or contained union),
>
> --- a type that is a (possibly cv-qualified) base class type of the
> dynamic type of the object,
>
> --- a char or unsigned char type.
>
> I think you're overloooking that an lvalue of type T can come from a
> char array. Otherwise, malloc, operator new, std::vector, and just
> about every other use of dynamic memory in C++ would be invalid. All
> you have to do is static_cast a void* to a T* and dereference it.
I disagree. I believe the "effective type" wording from C99 is correct
(or at least it captures the intent). If you don't agree, consider what
would happen if allocated memory or if a type-pun through a void* cast,
like you suggest, were legal: you would get the same sort of aliasing
issues that would come up if the "active member of a union" wording
weren't in the C++ standard and an optimizing compiler would have to
assume that every object can alias at that point and prove otherwise
without using information from the type system.
Please read at Lawrence Kirbiy's post in this thread (watch for
wrapping):
http://groups-beta.google.com/group/comp.lang.c/browse_frm/thread/e818f0462e0c70ce/cc3bbbdd91eddc61#cc3bbbdd91eddc61
The whole thread is about writing your own allocator using a suitably
aligned static character array (i.e. it basically describes one
possible use for aligned_storage). His resolution (which I agree with)
makes it impossible to write your own allocator on a strict standards
conforming compiler (this treats the standard allocation functions as
special). I agree that this is very, very unfortunate but the aliasing
rules would need to be changed somehow (very hard) in order to allow
aligned_storage to be used in that manner.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: dave@boost-consulting.com (David Abrahams)
Date: Thu, 7 Jul 2005 22:27:48 GMT Raw View
"Me" <anti_spam_email2003@yahoo.com> writes:
> David Abrahams wrote:
>> "Me" <anti_spam_email2003@yahoo.com> writes:
>>
>> > This instantiation of of aligned_storage must somehow magically
>> > contain any arbitrary T as one of its members (and not construct
>> > it), otherwise there are no legal ways this can work in terms of
>> > 3.10/15.
>>
>> Let's see:
>>
>> If a program attempts to access the stored value of an object
>> through an lvalue of other than one of the fol- lowing types the
>> behavior is undefined 48):
>>
>> --- the dynamic type of the object,
>>
>> --- a cv-qualified version of the dynamic type of the object,
>>
>> --- a type that is the signed or unsigned type corresponding to the
>> dynamic type of the object,
>>
>> --- a type that is the signed or unsigned type corresponding to a
>> cv-qualified version of the dynamic type of the object,
>>
>> --- an aggregate or union type that includes one of the
>> aforementioned types among its members (including, recursively,
>> a member of a subaggregate or contained union),
>>
>> --- a type that is a (possibly cv-qualified) base class type of the
>> dynamic type of the object,
>>
>> --- a char or unsigned char type.
>>
>> I think you're overloooking that an lvalue of type T can come from a
>> char array. Otherwise, malloc, operator new, std::vector, and just
>> about every other use of dynamic memory in C++ would be invalid. All
>> you have to do is static_cast a void* to a T* and dereference it.
>
> I disagree. I believe the "effective type" wording from C99 is correct
> (or at least it captures the intent).
I can tell you that the C++ standard is based on C90, not on C99,
which was finalized after the C++ standard.
Saying that C99 wording captures the intent of the C++ standard is
pure speculation on your part.
> If you don't agree, consider what would happen if allocated memory
> or if a type-pun through a void* cast, like you suggest, were legal:
But allocated memory *is* specifically legal! Certain type puns, too,
are legal.
> you would get the same sort of aliasing issues that would come up if
> the "active member of a union" wording weren't in the C++ standard
> and an optimizing compiler would have to assume that every object
> can alias at that point and prove otherwise without using
> information from the type system.
Maybe you should spell out what you mean by "aliasing issues" with a
clear illustration of the assumptions a compiler is forced to make,
because none of what you've said above is clear to me.
That said, a conclusion that C++ compilers have to allow for the
possibility of suboptimal aliasing doesn't disprove any premises. It
is well known that a conforming C++ compiler has to assume more things
can alias than some of us would like. That's one of the reasons some
people use FORTRAN for numerics (other C++ techniques can often be
used to counteract the aliasing disadvantage).
> Please read at Lawrence Kirbiy's post in this thread (watch for
> wrapping):
I use Gnus; no worries.
> http://groups-beta.google.com/group/comp.lang.c/browse_frm/thread/e818f0462e0c70ce/cc3bbbdd91eddc61#cc3bbbdd91eddc61
>
> The whole thread is about writing your own allocator using a suitably
> aligned static character array (i.e. it basically describes one
> possible use for aligned_storage). His resolution (which I agree with)
> makes it impossible to write your own allocator on a strict standards
> conforming compiler (this treats the standard allocation functions as
> special).
In C99, because of the unfortunate way they formulated "effective
type," it seems there is a problem. But C++ doesn't have that problem
because it incorporates C90, not C99, by reference.
> I agree that this is very, very unfortunate but the aliasing
> rules would need to be changed somehow (very hard) in order to allow
> aligned_storage to be used in that manner.
Your argument seems to be founded on conclusions based on the C99
standard.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Me" <anti_spam_email2003@yahoo.com>
Date: Sat, 2 Jul 2005 14:40:23 CST Raw View
Without knowing any better, I would say it's useful for implementing
boost::variant, using placement new on it and accessing it through a
type pun, and implementing your own allocator by having an aligned
large static character buffer and chopping it up into pieces manually.
Unfortunately, thanks to the aliasing rules, it doesn't look like it
can be done for an arbitrary type so aligned_storage is only useful for
chopping up memory returned from a dynamic memory allocation function
(if we take C99's "effective type" wording as canon). Lets just take a
sample implementation straight from the wording of TR1 4.8/1:
union type {
unsigned char __data[Len];
Aligner __align;
};
For this to be used for any arbitrary type, Aligner must be some
magical struct/union that contains every single type that is compatible
with whatever arbitrary type you give it. That in itself would be
somewhat useful because it would allow type puns that bypass aliasing
rules (search google groups for "norestrict"), but it leaves a bad
taste in my mouth to rely on this magical aliasing averting
struct/union.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "msalters" <Michiel.Salters@logicacmg.com>
Date: Tue, 5 Jul 2005 12:09:41 CST Raw View
Me schreef:
> Without knowing any better, I would say it's useful for implementing
> boost::variant, using placement new on it and accessing it through a
> type pun, and implementing your own allocator by having an aligned
> large static character buffer and chopping it up into pieces manually.
> Unfortunately, thanks to the aliasing rules, it doesn't look like it
> can be done for an arbitrary type so aligned_storage is only useful for
> chopping up memory returned from a dynamic memory allocation function
> (if we take C99's "effective type" wording as canon). Lets just take a
> sample implementation straight from the wording of TR1 4.8/1:
>
> union type {
> unsigned char __data[Len];
> Aligner __align;
> };
>
> For this to be used for any arbitrary type, Aligner must be some
> magical struct/union that contains every single type that is compatible
> with whatever arbitrary type you give it. That in itself would be
> somewhat useful because it would allow type puns that bypass aliasing
> rules (search google groups for "norestrict"), but it leaves a bad
> taste in my mouth to rely on this magical aliasing averting
> struct/union.
You're missing three points. One, the point of the TR1 is to add new
stuff to the standard. If the standard says it's OK, it's OK even
when other more general wording would suggest it's undefined behavior.
This applies doubly so when sample implementations are shown.
Secondly, aliasing rules don't apply here. Every object could be
accessed via an unsigned char*, and __data has that type.
Finally, the standard describes many works of magic. Aliaser is no
more magic then e.g. type_info or operator new. That magic is of course
a lot easier if you know the target. On a platform without alignment,
it's *really* easy.
HTH,
Michiel Salters
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]