What is the purpose of std::aligned_storage?
You can use std::aligned_storage
whenever you wish to decouple memory allocation from object creation.
You claim:
Also it is usable only with POD types.
But this is not true. There is nothing preventing std::aligned_storage
from being used with non-POD types.
The example on cppreference provides a legitimate use case:
template<class T, std::size_t N> class static_vector { // properly aligned uninitialized storage for N T's typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N]; std::size_t m_size = 0; ...
The idea here is that once the static_vector
is constructed, memory is immediately allocated for N
objects of type T
, but no objects of type T
are created yet.
You cannot do that with a simple T data[N];
array member, because this would immediately run T
's constructor for each element, or wouldn't even compile if T
is not default-constructible.
First, #pragma
directives are not portable. The Standard doesn't define any mandatory pragmas that must be supported, so every compiler is free to define its own set. But std::aligned_storage
is required to simply work no matter what compiler you're using. The compiler library writers might define it in terms of pragmas, attributes, or compiler extensions, but a user can just #include <type_traits>
and start using it.
And it's not true that "it is usable only with POD types". In fact, one common way of using aligned_storage
is as a chunk of memory where other objects of any type can be manually created and destroyed. It or something like it can be used to implement things like std::optional
and std::variant
.
To show the idea behind this, here's the start of writing a class similar to std::optional
:
#include <type_traits>
#include <memory>
template <typename T>
class my_optional
{
private:
std::aligned_storage_t<sizeof(T), alignof(T)> m_storage;
bool m_valid;
public:
constexpr my_optional() noexcept : m_valid(false) {}
constexpr my_optional(const T& obj)
noexcept(std::is_nothrow_copy_constructible<T>::value)
: m_valid(false)
{
new(static_cast<void*>(&m_storage)) T(obj);
m_valid = true;
}
constexpr const T& operator*() const
{
return *static_cast<const T*>(static_cast<const void*>(&m_storage));
}
constexpr T& operator*()
{
return *static_cast<T*>(static_cast<void*>(&m_storage));
}
~my_optional()
{
if (m_valid)
operator*().~T();
}
// Much more, to obey the Rule Of Five and add more functionality...
};
std::aligned_storage
manages aligned storage. Whether you place POD or non-POD objects in the storage is irrelevant.
The purpose of std::aligned_storage
is that it provides a standardized higher-level utility for managing aligned storage, so that you can write cleaner code with less hassles.