char array as storage for placement new

后端 未结 5 1613
[愿得一人]
[愿得一人] 2020-12-31 16:43

Is the following legal C++ with well-defined behaviour?

class my_class { ... };

int main()
{
    char storage[sizeof(my_class)];
    new ((void *)storage) m         


        
相关标签:
5条回答
  • 2020-12-31 17:07

    The char array may not be aligned correctly for the size of myclass. On some architectures, that means slower accesses, and on others, it means a crash. Instead of char, you should use a type whose alignment is equal to or greater than that of the struct, which is given by the largest alignment requirement of any of its members.

    #include <stdint.h>
    
    class my_class { int x; };
    
    int main() {
        uint32_t storage[size];
        new(storage) my_class();
    }
    

    To allocate enough memory for one my_class instance, I think size ought to be sizeof(my_class) / sizeof(T), where T is whichever type you use to get the correct alignment.

    0 讨论(0)
  • 2020-12-31 17:09

    It is at least problematic due to alignment.

    On most Non-Intel architecture the code will generate a "bus error" due to wrong alignment or be extremely slow because of processor traps needed to fix the unaligned memory access.

    On Intel architecture this will normally just be a bit slower than usual. Except if some SSE operations are involved, then it may also crash.

    0 讨论(0)
  • 2020-12-31 17:13

    Yes, it's problematic. You simply have no guarantee that the memory is properly aligned.

    While various tricks exist to get storage with proper alignment, you're best off using Boost's or C++0x's aligned_storage, which hide these tricks from you.

    Then you just need:

    // C++0x
    typedef std::aligned_storage<sizeof(my_class),
                                    alignof(my_class)>::type storage_type;
    
    // Boost
    typedef boost::aligned_storage<sizeof(my_class),
                            boost::alignment_of<my_class>::value>::type storage_type;
    
    storage_type storage; // properly aligned
    new (&storage) my_class(); // okay
    

    Note that in C++0x, using attributes, you can just do this:

    char storage [[align(my_class)]] [sizeof(my_class)];
    
    0 讨论(0)
  • 2020-12-31 17:14

    In case anyone wants to avoid Boost or C++1x, this complete code works both in GCC and MSVC. The MSVC-specific code is based on Chromium's aligned_memory.h. It's a little more complex than the GCC version, because MSVC's __declspec(align(.)) only accepts literal alignment values, and this is worked around using template specialization for all possible alignments.

    #ifdef _MSC_VER
    
    template <size_t Size, size_t Align>
    struct AlignedMemory;
    
    #define DECLARE_ONE_ALIGNED_MEMORY(alignment) \
    template <size_t Size> \
    struct __declspec(align(alignment)) AlignedMemory<Size, alignment> { \
        char mem[Size]; \
    };
    
    DECLARE_ONE_ALIGNED_MEMORY(1)
    DECLARE_ONE_ALIGNED_MEMORY(2)
    DECLARE_ONE_ALIGNED_MEMORY(4)
    DECLARE_ONE_ALIGNED_MEMORY(8)
    DECLARE_ONE_ALIGNED_MEMORY(16)
    DECLARE_ONE_ALIGNED_MEMORY(32)
    DECLARE_ONE_ALIGNED_MEMORY(64)
    DECLARE_ONE_ALIGNED_MEMORY(128)
    DECLARE_ONE_ALIGNED_MEMORY(256)
    DECLARE_ONE_ALIGNED_MEMORY(512)
    DECLARE_ONE_ALIGNED_MEMORY(1024)
    DECLARE_ONE_ALIGNED_MEMORY(2048)
    DECLARE_ONE_ALIGNED_MEMORY(4096)
    
    #else
    
    template <size_t Size, size_t Align>
    struct AlignedMemory {
        char mem[Size];
    } __attribute__((aligned(Align)));
    
    #endif
    
    template <class T>
    struct AlignedMemoryFor : public AlignedMemory<sizeof(T), __alignof(T)> {};
    
    0 讨论(0)
  • 2020-12-31 17:18

    As people have mentioned here, this won't necessarily work due to alignment restrictions. There are several ways to get the alignment right. First, if you have a C++0x-compliant compiler, you can use the alignof operator to try to force the alignment to be correct. Second, you could dynamically-allocate the character array, since memory from operator new is guaranteed to be aligned in such a way that anything can use it correctly. Third, you could try storing the character array in a union with some type that has the maximum possible alignment on your system; I believe that this article has some info on it (though it's designed for C++03 and is certainly not as good as the alignof operator that's coming out soon).

    Hope this helps!

    0 讨论(0)
提交回复
热议问题