问题
So, as I understended correctly, the main advantage of the std::aligned_storage is that it manage the align. Also it could be copied with memcpy. Also it is usable only with POD types.
But!
1) The POD types receive some align from compiler by default and we can remove the align by #pragma pack(push, 1)
2) We can copy POD with memcpy by default (we shouldnt do something for this ability)
So I cant get actually for which purposes do we need the std::aligned_storage?
回答1:
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.
回答2:
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...
};
回答3:
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.
来源:https://stackoverflow.com/questions/50271304/for-which-purposes-needs-stdaligned-storage