13

In C++03 code, how would I portably implement an unsigned char[sizeof(T)] buffer that has the same size and alignment as that of a given type T?

For example:

template<class T>
void test()
{
    unsigned char buffer[sizeof(T)];   // <----- how do I ensure this is aligned?
    if (some_condition())
    {
        T *const obj = new(buffer) T();
        // ...
        obj->~T();
    }
    else { /* use 'buffer' for something else */ }
}

Is this even possible, or are you forced to use compiler extensions in order to implement this?

user541686
  • 205,094
  • 128
  • 528
  • 886
  • Interesting question. +1 for remembering to manually hit the destructor (though I'm somewhat at a loss how you're doing so through a `const`. I really need to brush up on my `const` placements). – WhozCraig Aug 19 '13 at 21:39
  • @WhozCraig: Thanks. Note the pointee isn't const, the pointer itself is. :) – user541686 Aug 19 '13 at 21:41
  • Yeah, I just saw that. =P – WhozCraig Aug 19 '13 at 21:42
  • Is it ok to assume the alignment restriction is an argument (template or functional) supplied (like `template` where N is your required boundary? Just trying to think of how I would play with the size of the buffer and its beginning and end to drop an object in the right place. – WhozCraig Aug 19 '13 at 21:45
  • @WhozCraig: Not really, because how do I know what the required boundary is? – user541686 Aug 19 '13 at 21:47
  • Ah.. ok. Seeing Gregory's answer it looks like you're shooting for alignment to the platform, so I'll just keep watch for awhile. Thanks. – WhozCraig Aug 19 '13 at 21:48
  • use 2*sizeof(T)-1 .. Or better N*sizeof(T)+sizeof(K)-1 (where K is required alignement and N number of objecst you want to have at once) and there's enough space to always align the type in the char buffer. To get the proper aligned address you can look at opensource stuff like Ogre's aligned allocation. There's a simple bit manipulation to get aligned address (right now I can't remember it) – CoffeDeveloper Aug 20 '13 at 05:48
  • @DarioOO: Are you referring to [this](http://stackoverflow.com/a/6320500/541686) bit manipulation? – user541686 Aug 20 '13 at 06:06
  • yeah it looks familiar. It should be right.. anyway regarding alignment: http://lemire.me/blog/archives/2012/05/31/data-alignment-for-speed-myth-or-reality/ Unless particular cases on modern processors alignment penality is much smaller than older processors so it even may be neglictable. – CoffeDeveloper Aug 20 '13 at 07:08

2 Answers2

7

In his Guru Of The Week #28 column, Herb Sutter uses a union but it's less robust than Boost's efforts.

Boost's aligned_storage solves the gory details for you. If you look at its implementation, you'll see it uses MSCV's __alignof or GCC's __alignof__ as well as another template: type_with_alignment.

From my own codebase, I once used (derived from the GOTW link above):

#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 150020706)
#  pragma warning(push)
#  pragma warning(disable: 4371)
#endif // #if (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 150020706)
      union AlignedStorage
      {
        char        storage[sizeof(T)];
        int16       dummy0;
        int32       dummy1;
        int64       dummy2;
        float       dummy3;
        double      dummy4;
        long double dummy5;
        void        (*dummy6)();
        struct      dummy7;
        int         dummy7::*dummy8;
#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140050215)
#  pragma warning(push)
#  pragma warning(disable: 4121)
#endif // #if (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140050215)
        int         (dummy7::*dummy9)(int);
#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140050215)
#  pragma warning(pop)
#endif // #if (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140050215)

      }; // AlignedStorage
#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 150020706)
#  pragma warning(pop)
#endif // #if (defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 150020706)

These days I would just rely on Boost since it likely covers many more corner cases and compiler specificities

Gregory Pakosz
  • 69,011
  • 20
  • 139
  • 164
  • Two issues: (1) I'm asking how this is **implemented** in the first place. Is there a portable way to do it or does it require compiler extensions? (2) What do I give it as the second template parameter (the alignment)? – user541686 Aug 19 '13 at 21:38
  • After your edit #1 -- so you're saying it requires compiler extensions? – user541686 Aug 19 '13 at 21:45
  • After your edit #2 -- yes I can combine all possible types to get the maximum alignment but that over-aligns data and wastes space in many cases. I'm trying to get the **same** alignment as the type; not more, not less. – user541686 Aug 19 '13 at 21:48
  • C++03 compiler extension is needed to get back the alignment of a type. If you know the alignment, you can use a template similar to Boost's `type_with_alignment` (and a first glimpse at it reveals the implementation is not trivial) and in fact `type_with_alignment` requires `__is_pod(T)` extension – Gregory Pakosz Aug 19 '13 at 21:50
  • @Mehrdad: So, make a union of the type you want to align, and the char[]. – cHao Aug 19 '13 at 21:51
  • @GregoryPakosz: Okay so I need compiler extensions. That answers my question, thanks. :) – user541686 Aug 19 '13 at 21:51
  • @cHao: I don't think that's allowed for non-PODs in C++03...? – user541686 Aug 19 '13 at 21:52
  • @Mehrdad I believe you're correct. I likewise didn't think non-PODs were allowed membership into unions. – WhozCraig Aug 19 '13 at 21:53
  • Your `AlignedStorage` is suboptimal if you only want to store types smaller that pointer to member or pointer to member function. It also does not work correctly for SIMD types whose alignment requirement is larger than that of any of built-in types. – Maxim Egorushkin Aug 20 '13 at 08:41
  • In which case, one can for instance add `__m128i` to the union right? And well I suspect that kind of aligned storage is mainly used for PIMPL with stack allocation. I would say any SIMD approach would define the problem in another way. – Gregory Pakosz Aug 20 '13 at 08:46
  • @GregoryPakosz Putting more types with large alignments in that union results in even more suboptimal storage (waste of space). The right solution is to align that union with `__attribute__((aligned(__alignof(T))))` - this is exactly what `boost::type_with_alignment` does for you. – Maxim Egorushkin Aug 20 '13 at 09:43
  • And it's exactly what I recommend using. It's obvious the code I pasted is suboptimal yet it can be acceptable in certain use cases when you don't want to bring Boost within your project. Would you prefer I remove the code excerpt? – Gregory Pakosz Aug 20 '13 at 09:47
2

The reason compiler extensions like __alignof and __attribute__((aligned(n)) exist is that determining and enforcing alignment can not be implemented portably in C and C++. I.e. the standard requires no means to do that.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • I'm not sure if you're trying to say it *isn't* implemented portably, or if it really *can't* be implemented portably. Which one do you mean? – user541686 Aug 19 '13 at 23:02
  • c/c++ standard just leave freedom to the compiler, everything must still be aligned to char at least. In C++11 alignement is part of the standard infact, alignment is probably portable to most existing architectures. – CoffeDeveloper Aug 20 '13 at 05:44
  • @Mehrdad C++ standard does not require facilities for that, hence the extensions. – Maxim Egorushkin Aug 20 '13 at 08:28
  • @DarioOO _everything must still be aligned to char at least_ - can it possibly be aligned less? _In C++11 alignement is part of the standard infact_ - same is true for C++98. Not sure what point you are trying to make. – Maxim Egorushkin Aug 20 '13 at 08:30