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...
};