Placement-new address alignment
Asked Answered
K

3

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.

Katiekatina answered 1/3, 2017 at 1:22 Comment(5)
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...Roundish
We have no information regarding Fred, sizeof(Fred) may be 0 or 1.Laurentian
@Laurentian if it's not specified, you shouldn't assume anything. And sizeof cannot be 0 as per the Standard.Katiekatina
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.Laurentian
@Laurentian No, from the answers below, the example is wrong, when no assumption is made. You are making an assumption.Katiekatina
C
20

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.

Canice answered 1/3, 2017 at 1:24 Comment(4)
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?Rosemonde
Implicit casts to and from void* are only legal in C. C++ has a stricter type system.Committeeman
@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.Canice
@Committeeman No, implicit casts to void* are OK in C++ as well. The other way around doesn't work.Rosemonde
R
11

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)];
Roundish answered 1/3, 2017 at 1:33 Comment(0)
T
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))).

Tamera answered 1/3, 2017 at 1:29 Comment(5)
Or make a union with the char array and the alignment type.Haitian
your statement on heap allocation for "any type" is wrong. See this comment #6974495Katiekatina
@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 #13097768Tamera
std::alignas? I thought alignas is a C++ keyword, not a member of the std namespace.Immunogenetics
@TobySpeight: Indeed it's a keyword, my fault.Tamera

© 2022 - 2024 — McMap. All rights reserved.