From: Howard Hinnant <hinnant@twcny.rr.com>
>> On Jun 14, 2006, at 6:55 AM, David Abrahams wrote:
>>
>>> I think what the OP is looking for is called boost::shared_ptr ;-)
>>


Actually,  *one* of my uses is a bit more devious - more like the short-string optimization - you might want to call it "embedded_ptr<T, size>".  Where it reserves enough space for T (because you explicitly supply the size) and acts like a pointer to T otherwise.  You might call it a hack and/or dangerous, and I won't entirely disagree.  It does have a static assert on the implementation side (where T is known) to ensure size == sizeof(T), but it is still dangerous if the client compiles with different settings than the implementation.  However, knowing these caveats, it may still be useful in cases where you really want/need to avoid the allocation overhead (and still want to separate implementation from interface).

If that use-case is not 'worthy' enough to be an argument for default-alignment-based-on-size, a more typical case would probably be a custom allocator.  In particular, a small-block allocator.  If I need to allocate 4 bytes, I don't want to allocate it on a 16 byte boundary.  Now maybe if I am writing an allocator am doing platform-dependent things anyhow, but I don't necessarily think so.

Another use of aligned_storage (where T IS complete) is a more noble cause - handling thread safe static locals:
void func()
{
   static thread_safe_static_local<Foo> foo;  // foo's constructor called once, THREADSAFELY
   ...
}

Not sure why I bother to mention that, other than the fact it shares much of the same code as the embedded_ptr.

P.S. even if some of you have to hold your nose when thinking of the hack that is embedded_ptr, what do people think of the name? I've been throwing around some different names (ie embedded_incomplete) but until Dave mentioned shared_ptr, I hadn't thought of embedded_ptr.


>> shared_ptr can't compete with this application performance-wise.
>
> Well, it depends how expensive it is to copy your small object.  If it
> turns out that T is a vector, and it fits in your local buffer, when
> Container is copied it might be a lot cheaper to use shared_ptr.

Sure.  I'm responding to the assertion that you need a known complete
type to effectively use aligned_storage.  My point is that there
exist valuable use cases where this assertion is false.  The
existence of these cases is what makes the defaulted alignment
template parameter on aligned_storage valuable.

Tony's observation is that this default value is even more valuable
if it is dependent upon the buffer size, which again I fully agree
with.  If you want a 5 byte buffer that is aligned to the "most
stringent alignment requirements" (definition found in 5.3.4p10), an
alignment of 16 (for example) is likely to be correct but overkill.
I had personally settled on 8 for this particular example but Tony
makes a convincing argument for 4 being the optimum (all numbers
assuming current popular desktop processors and quoted just for
example).


Actually, after thinking about it a bit, I'm now tempted to say a 5 byte buffer should have 1 byte alignment.
eg (given a typical platform):

struct test_alignment
{
   int x;
   char y;
};

At first, I thought that any 5 byte structure could have AT MOST a 4 byte alignment requirement because it could have an int as the first param, as in the example above.  However, if it does have 4 byte alignment, its size will be 8, so that an array of them will align to 4 bytes. (Howard, you hinted at this in another email thread).
So,
If sizeof(test_alignment) == 5, then the alignment must really be 1 (ie there is probably a pragma pack(1) in play).

Either way, the alignment is NOT 16 (or whatever max alignment might be), but derivable from the size of the structure.

Also, in any case, for boost::type_with_alignment<5> doesn't compile.  I think it should at least do something (or else the standard/docs need to have lots of wording explaining which ints work and which do not).

Similarly, aligned_storage has the same 'problem' and basically only works with alignment_of (or something that does the same thing).  Since that is the case anyhow, I would suggest that aligned_storage be replaced with:

storage_for<T, count = 1>;

(which can be written in terms of aligned_storage and alignment_of, but since the two are tied together, and typically used together, why not just supply what is really wanted).

So really I'd like:

   storage_for_type<T, size_t count = 1>
and
   storage_for_size<size_t>

where storage_for_size determines the minimum necessary alignment based on the size, as discussed.


-Howard

Tony