C++17 introduced a new type, std::byte, so now we finally have a first-class citizen type to represent bytes in memory. Besides being a novelty in the standard, the C++ rules for object creation, start and end of life, aliasing etc. are fairly complicated an unintuitive most of the times, so whenever I feel std::byte is the right tool I also get nervous and reluctant to use it, for fear of unintentionally summoning the Undefined Behavior Balrogs.
One such case is a buffer to be used with placement new:
#include <memory>
#include <cstddef>
#include <type_traits>
struct X { double dummy[4]; char c; };
auto t1()
{
// the old way
std::aligned_storage_t<sizeof(X)> buffer;
X* x = new (&buffer) X{};
x->~X();
}
auto t2()
{
// the new way?
std::byte buffer[sizeof(X)];
X* x = new (&buffer) X{};
x->~X();
}
Is t2 perfectly safe and equivalent with t1?
In response to alignment issues, what about:
auto t3()
{
alignas(X) std::byte buffer[sizeof(X)];
X* x = new (&buffer) X{};
x->~X();
}
No. In fact, both are bad.
t2is bad for the reason NathanOliver indicates: it's underaligned. You'd need to write:t1also kind of has this problem, in that you almost certainly want to writealigned_storage_t<sizeof(X), alignof(X)>and not justaligned_storage_t<sizeof(X)>. IfXwere overaligned, you would lose that here. IfXwas just large but had no alignment requirement, you would end up with a relatively overaligned storage.t1is also bad for an especially peculiar reason:aligned_storagedoesn't quite guarantee what you think it guarantees. In particular, it guarantees that anXcan fit inaligned_storage<sizeof(X)>, but it does not guarantee that it can fit exactly. The specification is simply:That is,
aligned_storage<16>::typeis guaranteed to be at least 16 bytes, but a conforming implementation could easily give you 32. Or 4K. That in addition to the problem of usingaligned_storage<16>by accident instead ofaligned_storage_t<16>.This is why P1413 exists as a paper:
aligned_storageis kind of bad.So the real answer is actually just to write something like libstdc++'s
__aligned_membuf: