27

If I understand it correctly, the main advantage of the std::aligned_storage is that it manages the alignment. Also it can be copied with memcpy() and can be used with POD types.

But!

1) The POD types are aligned by compiler by default and we can override this compiler's alignment using #pragma pack(push, 1)

2) We can copy POD with memcpy() by default (we shouldn't do something for this ability)

So I don't really understand why do we need std::aligned_storage?

ultimate cause
  • 2,264
  • 4
  • 27
  • 44
AeroSun
  • 2,401
  • 2
  • 23
  • 46

3 Answers3

34

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.

  • 1
    .. and the alternative is a `char[]` but this will/may not be properly aligned because the language has no way of knowing what kind of thing you want to construct in it. All of that together answers the OP's "doubt" :) – Lightness Races in Orbit May 10 '18 at 11:35
  • 3
    Just a note to future readers that `std::aligned_storage` and friends are deprecated in C++23: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1413r3.pdf – helmesjo Mar 09 '23 at 09:14
9

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...
 };
aschepler
  • 70,891
  • 9
  • 107
  • 161
5

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.

Lingxi
  • 14,579
  • 2
  • 37
  • 93