15

According to https://isocpp.org/wiki/faq/dtors#placement-new the address passed into placement-new has to be properly aligned. But the example it gives seems to contradict that.

char memory[sizeof(Fred)];

This buffer is most likely not aligned for Fred, since it's a dumb char[], so memory can point to pretty much anywhere. Then it does placement-new on this address.

Is the example contradicting the alignment requirement it says in the DANGER footnote?

That leads to a related question:

How can I create a buffer (either stack or heap) that is aligned for a type T (to use in placement-new of one or more T objects)?

By buffer I mean a char[] or void* buffer of some size, not a T[] because that would be object allocation which defeats the point of doing placement-new afterwards.

Thank you.

PoweredByRice
  • 2,479
  • 1
  • 20
  • 26
  • Unless a char[N] is aligned to objects of size N then yes, it contradicts the footnote. Gotta check if the standard has anything to say about this... – akappa Mar 01 '17 at 01:27
  • We have no information regarding `Fred`, `sizeof(Fred)` may be 0 or 1. – YSC Mar 01 '17 at 10:19
  • @YSC if it's not specified, you shouldn't assume anything. And `sizeof` cannot be 0 as per the Standard. – PoweredByRice Mar 01 '17 at 14:02
  • I agree, you should not assume their example is wrong. Especially when it is given with a warning saying when alignment would be a problem. – YSC Mar 01 '17 at 14:54
  • 1
    @YSC No, from the answers below, the example is wrong, when no assumption is made. You are making an assumption. – PoweredByRice Mar 01 '17 at 15:19

3 Answers3

19

Use the alignas keyword:

alignas(Fred) char buf[sizeof(Fred)];
::new (static_cast<void*>(buf)) Fred;

Or use std::aligned_storage if you prefer a library wrapper around this construction.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 1
    Upvoted, but why do you need a cast to `void*`? `::new (buf) Fred;` seems to work just fine, any pointer can be implicitly converted to `void*`, can't it? – vsoftco Mar 01 '17 at 01:38
  • Implicit casts to and from void* are only legal in C. C++ has a stricter type system. – JeremiahB Mar 01 '17 at 01:43
  • 9
    @vsoftco: That one may be overloaded. The form I chose cannot be overloaded. It depends on what amount of customization you want to allow; you can also say `new` instead of `::new` to consider class overloads. – Kerrek SB Mar 01 '17 at 01:44
  • 10
    @JeremiahB No, implicit casts to `void*` are OK in C++ as well. The other way around doesn't work. – vsoftco Mar 01 '17 at 01:45
10

About your first question: according to the answers to this related question yes, the example got it wrong:

Statically allocated arrays are aligned to sizeof(element_type) bytes -- for char it is 1 byte, which basically guarantees no alignment.

thus the array char memory[sizeof(Fred)] has no alignment guarantees for Fred.

The proper way of doing it is as follows (C++11):

alignas(Fred) char memory[sizeof(Fred)];
Community
  • 1
  • 1
akappa
  • 10,220
  • 3
  • 39
  • 56
3

For heap allocations just use std::malloc which it is guaranteed to allocate memory that is aligned for any type.

For stack allocations, if you have access to C++11, then you can use alignas as in

alignas(T) uint8_t data[sizeof(T)];

If you don't have access to C++11 then you must fallback to specific compiler attributes as GCC's __attribute__((aligned(N))).

T.C.
  • 133,968
  • 17
  • 288
  • 421
Jack
  • 131,802
  • 30
  • 241
  • 343
  • Or make a union with the char array and the alignment type. – Zan Lynx Mar 01 '17 at 01:32
  • your statement on heap allocation for "any type" is wrong. See this comment http://stackoverflow.com/questions/6973995/dynamic-aligned-memory-allocation-in-c11#comment23703633_6974009 – PoweredByRice Mar 01 '17 at 03:06
  • @PoweredByRice: you can't have a type which natively has an alignment greater than `std::max_align_t`, your original question isn't about alignment requirements for objects that have requirement which are not related to their definition (eg SSX or AVX requirements) so `std::malloc` is safe for any type, unless you have some specific requirements that you didn't mention. Please check http://stackoverflow.com/questions/13097268/what-are-the-alignment-limitations-of-the-standard-global-default-operator-new – Jack Mar 01 '17 at 03:11
  • 3
    `std::alignas`? I thought `alignas` is a C++ keyword, not a member of the `std` namespace. – Toby Speight Mar 01 '17 at 08:46
  • @TobySpeight: Indeed it's a keyword, my fault. – Jack Mar 01 '17 at 14:41