Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would I portably implement aligned stack storage in C++03?

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?

like image 415
user541686 Avatar asked Aug 19 '13 21:08

user541686


People also ask

Why does the stack need to be aligned?

Alignment is limiting addresses where data can be placed and is not limited to stacks. For example, 4-byte alignment would mean that all addresses have the lowest 2 bits always 0. The alignment often corresponds to the memory bus width in the hardware which can be several bytes wide.

How do you ensure byte alignment?

General Byte Alignment RulesStructures between 5 and 8 bytes of data should be padded so that the total structure is 8 bytes. Structures between 9 and 16 bytes of data should be padded so that the total structure is 16 bytes. Structures greater than 16 bytes should be padded to 16 byte boundary.

What is the alignment of malloc?

new and malloc, by default, align address to 8 bytes (x86) or 16 bytes (x64), which is the optimal for most complex data.

How does memory alignment work?

A memory access is said to be aligned when the data being accessed is n bytes long and the datum address is n-byte aligned. When a memory access is not aligned, it is said to be misaligned. Note that by definition byte memory accesses are always aligned.


2 Answers

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

like image 159
Gregory Pakosz Avatar answered Oct 01 '22 01:10

Gregory Pakosz


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.

like image 26
Maxim Egorushkin Avatar answered Oct 01 '22 03:10

Maxim Egorushkin