In order to ensure a user-specified memory alignment of certain data structures in C++, I think three use cases need to be taken care off and dealt with appropriately (if I am missing some use cases, feel free to add them):
- static memory allocation;
- dynamic memory allocation;
- memory allocation in containers (e.g.
std::vector
) and smart pointers (e.g.std::shared_ptr
).
C++11 takes care of the static memory allocation by adding the alignas
specifier which allows to manually specify the alignment. C++17 takes care of the dynamic memory allocation by implicitly overriding operator new
, operator new[]
, operator delete
and operator delete[]
. Though, I noticed that C++17 added overloads of these operators with an extra alignment parameter as well?
Containers like std::vector
can allocate a large block of raw memory for storing the container elements. The container elements can then be allocated by passing a pointer to some location in this block to operator new
(placement new). There is a similar situation for std::shared_ptr
which uses a control and data block that are allocated together in case std::make_shared
is called (which is different for std::unique_ptr
which only uses a data block, which will be allocated with operator new
after calling std::make_unique
). In order to ensure the correct memory alignment for container elements and the data block of std::shared_ptr
, the std
provides the possibility to pass an allocator which will be used for these allocations. Given that alignas
is specified for some data structure, is it still necessary to pass such an allocator to ensure the correct memory alignment in C++17? Or is this handled internally by std::vector
, std::shared_ptr
, etc. (by using alignof
)?
Visual Studio (which is closely connected to the MVC++ compiler) supports the alignas
and alignof
keywords since Visual Studio 2015. Because some Microsoft libraries are still maintained for Visual Studio 2013, the use of _declspec(align(...))
is ubiquitous. _declspec(align(...))
only takes care of the static memory allocation. To handle dynamic memory allocation, one typically publically inherit from the following stateless structure:
template< typename TDerived >
struct AlignedNew {
static void* operator new (size_t size) {
const size_t alignment = __alignof(TDerived);
static_assert(alignment > 8);
void* ptr = _aligned_malloc(size, alignment);
if (!ptr)
throw std::bad_alloc();
return ptr;
}
static void operator delete (void* ptr) {
_aligned_free(ptr);
}
static void* operator new[] (size_t size) {
return operator new(size);
}
static void operator delete[] (void* ptr) {
operator delete(ptr);
}
};
So I wonder if the combination of _declspec(align(...))
+ inheriting this struct and alignas(...)
provides the same functionality or if alignas(...)
provides the same but even more functionality than _declspec(align(...))
+ inheriting this struct? And if this is the case, can I safely replace the _declspec(align(...))
with alignas(...)
and remove the AlignedNew
structure?
Their is a similar question about this last part from the pre-C++17 era, but the first dot of the accepted and only answer is not very profound, imho.
Note that multiple C++ standards are mentioned in this question and multiple MVC++ versions which are only partial implementations of various of these C++ standards. I am mostly concerned with C++17 (and the latest iteration of Visual Studio 2017)