IsoCpp.org offers a FAQ regarding placement new:
The example they provide is:
#include <new> // Must #include this to use "placement new"
#include "Fred.h" // Declaration of class Fred
void someCode()
{
char memory[sizeof(Fred)]; // Line #1
void* place = memory; // Line #2
Fred* f = new(place) Fred(); // Line #3 (see "DANGER" below)
// The pointers f and place will be equal
// ...
}
Wouldn't the above code violate C++'s strict aliasing rule since place
and memory
are different types, yet reference the same memory location?
(I know that pointers of type char
can alias any other type, but here we seem to have a void*
aliasing a char*
, which is not allowed from what I understand?)
I suspect that most memory allocators would also violate the strict aliasing rule in a similar manner. What is the proper way to comply with the strict aliasing rule when using placement new?
Thank you
What is the proper way to comply with the strict aliasing rule when using placement new?
The correct way is to use std::aligned_storage
. That code sample doesn't guarantee correct storage alignment for Fred
, so it should not be used.
The correct way to do this is:
#include <new> // For placement new
#include <type_traits> // For std::aligned_storage
struct Fred {
// ...
};
void someCode() {
std::aligned_storage<sizeof(Fred), alignof(Fred)>::type memory;
// Alternatively, you can remove the "alignof(Fred)" template parameter if you
// are okay with the default alignment, but note that doing so may result in
// greater alignment than necessary and end up wasting a few bytes.
Fred* f = new(&memory) Fred();
}
Wouldn't the above code violate C++'s strict aliasing rule since place and memory are different types, yet reference the same memory location?
Now, as for your concerns about aliasing between f
, place
, and memory
in the original code, note that there isn't any aliasing violation. The strict aliasing rule means that you can't "dereference a pointer that aliases an incompatible type". Since you can't dereference a void*
(and it's legal to convert a pointer to/from a void*
), there's no risk of place
causing a strict aliasing violation.