Suppose I have a type template parameter T.
And suppose I have a std::aligned_storage
as follows:
typename std::aligned_storage<sizeof(T), alignof(T)>::type storage;
I want to placement new a T into the storage
.
What is the standard-compliant pointer value/type to pass to the placement new operator, and how do I derive that from storage
?
new (& ???) T(a,b,c);
For example:
new (&storage) T(a,b,c); new (static_cast<void*>(&storage)) T(a,b,c); new (reinterpret_cast<T*>(&storage)) T(a,b,c); new (static_cast<T*>(static_cast<void*>(&storage));
Which of the above (if any) are compliant, and if none, what is the better way?
The most paranoid way is
::new ((void *)::std::addressof(storage)) T(a, b, c);
Explanation:
::std::addressof
guards against overloaded unary operator&
on storage
, which is technically allowed by the standard. (Though no sane implementation would do it.) The ::std
guards against any non-top-level namespaces (or classes) called std
that might be in scope.(void *)
(which in this case is the equivalent of a static_cast
) ensures that you call the placement operator new
taking a void *
rather than something else like decltype(storage) *
.::new
skips any class-specific placement operator new
s, ensuring that the call goes to the global one.Together, this guarantees that the call goes to the library placement operator new
taking a void *
, and that the T
is constructed at where storage
is.
In most sane programs, though,
new (&storage) T(a,b,c);
should be sufficient.
The placement allocation function is described as follows (C++14 n4140 18.6.1.3):
void* operator new(std::size_t size, void* ptr) noexcept;
Returns:
ptr
.Remarks: Intentionally performs no other action.
20.10.7.6 table 57 describes aligned_storage<Len, Align>
thus:
The member typedef
type
shall be a POD type suitable for use as uninitialized storage for any object whose size is at most Len and whose alignment is a divisor of Align.
This implies that in your case, &storage
is suitably aligned for holding an object of type T
. Therefore, under normal circumstances1, all 4 ways you've listed of calling placement new
are valid and equivalent. I would use the first one (new (&storage)
) for brevity.
1 T.C. correctly pointed out in the comments that it is technically possible for your program to declare an overload of the allocation function taking a typename std::aligned_storage<sizeof(T), alignof(T)>::type*
, which would then be selected by overload resolution instead of the library-provided 'placement new' version.
I would say this unlikely in at least 99.999% of cases, but if you need to guard against that as well, use one of the casts to void*
. The direct static_cast<void*>(&storage)
is enough.
Also, if you're paranoid to this level, you should probably use ::new
instead of just new
to bypass any class-specific allocation functions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With