Для каких целей нужен std :: align_storage? - PullRequest
0 голосов
/ 10 мая 2018

Итак, как я правильно понял, главное преимущество std :: align_storage состоит в том, что он управляет выравниванием.Также это может быть скопировано с memcpy.Также его можно использовать только с типами POD.

Но!

1) Типы POD по умолчанию получают выравнивание от компилятора, и мы можем удалить выравнивание с помощью #pragma pack (push, 1)

2) По умолчанию мы можем скопировать POD с memcpy (мы не должны что-то делать для этой способности)

Так что я не могу понять, для каких целей нам нужен std :: align_storage?

Ответы [ 3 ]

0 голосов
/ 10 мая 2018

Во-первых, директивы #pragma не являются переносимыми. Стандарт не определяет никаких обязательных прагм, которые должны поддерживаться, поэтому каждый компилятор может определять свой собственный набор. Но std::aligned_storage требуется, чтобы просто работать независимо от того, какой компилятор вы используете. Авторы библиотек компиляторов могут определять его в терминах прагм, атрибутов или расширений компилятора, но пользователь может просто #include <type_traits> и начать использовать его.

И это не правда, что "это можно использовать только с типами POD". Фактически, одним из распространенных способов использования aligned_storage является использование фрагмента памяти, в котором другие объекты типа любого типа могут быть созданы и уничтожены вручную. Это или что-то подобное можно использовать для реализации таких вещей, как std::optional и std::variant.

Чтобы показать идею, стоящую за этим, вот начало написания класса, подобного 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...
 };
0 голосов
/ 10 мая 2018

std::aligned_storage управляет выравниванием хранилища. Помещаете ли вы POD или не POD объекты в хранилище, не имеет значения.

Цель std::aligned_storage состоит в том, чтобы предоставить стандартизированную высокоуровневую утилиту для управления выровненным хранилищем, чтобы вы могли писать более чистый код с меньшими трудностями.

0 голосов
/ 10 мая 2018

Вы можете использовать std::aligned_storage всякий раз, когда хотите отделить выделение памяти от создания объекта.

Вы заявляете:

Кроме того, его можно использовать только с типами POD.

Но это не так.Ничто не мешает использовать std::aligned_storage с типами, отличными от POD.

Пример cppreference предоставляет допустимый вариант использования:

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

Идея заключается в том, что после создания static_vector память немедленно выделяется для N объектов типа T, но объекты типа T еще не созданы.

Youне может сделать это с помощью простого T data[N]; члена массива, потому что это немедленно запустит конструктор T для каждого элемента, или даже не скомпилируется, если T не конструируется по умолчанию.

...