Char array as storage to host new

Is the following legitimate C ++ with well-defined behavior?

class my_class { ... }; int main() { char storage[sizeof(my_class)]; new ((void *)storage) my_class(); } 

Or is this problematic due to casting / alignment considerations of the pointer?

+7
source share
5 answers

Yes, this is problematic. You simply have no guarantee that the memory is correctly aligned.

While there are various tricks to get the correct alignment, you are better off using Boost or C ++ 0x aligned_storage , which hides these tricks from you.

Then you just need to:

 // 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 simply do this:

 char storage [[align(my_class)]] [sizeof(my_class)]; 
+12
source

As mentioned here, this will not necessarily work due to alignment restrictions. There are several ways to align correctly. First, if you have a compiler compatible with C ++ 0x, you can use the alignof operator to try to force the alignment to be correct. Secondly, you can dynamically allocate an array of characters, since the memory from the new operator is guaranteed to be aligned in such a way that everything can use it correctly. Thirdly, you can try to save an array of characters in combination with some type that has the highest possible alignment in your system; I believe that this article contains some information about this (although it is intended for C ++ 03 and, of course, not as good as the alignment operator that is coming soon).

Hope this helps!

+3
source

This is at least problematic due to alignment.

On most non-Intel architectures, the code will generate a β€œbus error” due to misalignment or be extremely slow due to processor traps needed to correct unaccepted memory access.

In Intel architecture, this will usually be slightly slower than usual. Unless some SSE operations are involved, it may also fail.

+2
source

If anyone wants to avoid Boost or C ++ 1x, this full code works in both GCC and MSVC. The specific MSVC code is based on Chromium aligned_memory.h . This is a bit more complicated than the GCC version, because MSVC __declspec(align(.)) Only accepts literal alignment values, and this is done using specialized 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)> {}; 
+2
source

The char array cannot be correctly aligned for the size of myclass . On some architectures, this means slower access, and on others, crash. Instead of char you should use a type whose alignment is equal to or greater than the value of struct , which is specified by the highest alignment requirement for 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 a single instance of my_class , I think that the size should be sizeof(my_class) / sizeof(T) , where T is of the type that you use for proper alignment.

0
source

All Articles