24 Temmuz 2020 Cuma

std::align_val_t

Giriş
Açıklaması şöyle. Bu new operator'un overload hali C++17 ile geliyor
_aligned_malloc() is a Windows-specific, non-portable function. Luckily, C++17 added the portable aligned_alloc() without an underscore. It also introduces a variant of new that allows aligned allocation.
Bu Özellik Neden Lazım
Örnek
Elimizde şöyle bir kod olsun. Bu yapı 16 byte yani 128 bitlik register'lara sığar
struct alignas(16) Vec3 {
  float x, y, z;
};
Açıklaması şöyle
Why might you need those functions? It’s because if you have some specific types, like a Vec3 that has to be allocated to 128bits alignment (so it can fit nicely in SIMD registers),
Bu  yapıyı new'leyelim
auto ptr = new Vec3[10];
Ama C++14 ile karşımıza şu problem çıkıyor.
To work with SSE you require the ptr to be aligned to 16-byte boundary, but in C++14 there’s no guarantee about this.
C++17 bu problemi çözüyor. Açıklaması şöyle
Fortunately, the C++17 standard fixes this by introducing allocation functions that honour the alignment of the object.

For example we have:
void* operator new[](std::size_t count, std::align_val_t al);
Now, when you allocate an object that has a custom alignment, then you can be sure it will be appropriately aligned.
Örnek
Elimizde şöyle bir kod olsunn
#include <cassert>
#include <cstdint>
#include <iostream>
#include <malloc.h>
#include <new>


class alignas(32) Vec3d {
  double x, y, z;
};


int main() {

    std::cout << "sizeof(Vec3d) is " << sizeof(Vec3d) << '\n';
    std::cout << "alignof(Vec3d) is " << alignof(Vec3d) << '\n';

    auto Vec = Vec3d{};
    auto pVec = new Vec3d[10];

    if(reinterpret_cast<uintptr_t>(&Vec) % alignof(Vec3d) == 0)
        std::cout << "Vec is aligned to alignof(Vec3d)!\n";
    else
        std::cout << "Vec is not aligned to alignof(Vec3d)!\n";

    if(reinterpret_cast<uintptr_t>(pVec) % alignof(Vec3d) == 0)
        std::cout << "pVec is aligned to alignof(Vec3d)!\n";
    else
        std::cout << "pVec is not aligned to alignof(Vec3d)!\n";

    delete[] pVec;
}
Açıklaması şöyle
The code shows a structure - Vec3d that uses three double fields; it also marks the type with alignas that makes the objects aligned to 32 bytes.

Then the example creates two objects: one on the stack and one on the free store.

Do they both have the same alignment (32 bytes)?

And another question:

Should you care about the alignment of your memory allocations?
C++14 ile çıktı olarak şunu alırız
sizeof(Vec3d) is 32
alignof(Vec3d) is 32
Vec is aligned to alignof(Vec3d)!
pVec is not aligned to alignof(Vec3d)!
C++17 ile çıktı olarak şunu alırız
sizeof(Vec3d) is 32
alignof(Vec3d) is 32
Vec is aligned to alignof(Vec3d)!
pVec is aligned to alignof(Vec3d)!
Açıklaması şöyle
In both compiler results, the alignment of objects on the stack is 32, as expected.

But for dynamic allocation it’s different:

In C++11 and C++14, there was no guarantee that memory allocated for types that are over-aligned honours that specific alignment. In our case we want Vec3d allocations to return pointers that are 32-byte aligned… but GCC 4.8.5 allocates differently.

How about C++17?

Now, in the newest standard, we have updated dynamic memory allocations, and now we have a guarantee that the memory will be aligned as requested.

As you see in GCC 9.1, the memory is now 32-byte aligned.
Örnek
Şöyle yaparız
#include <new>
...
MemoryBlock::MemoryBlock(size_t size, size_t alignment):
    p_rawMem((void *)new(std::align_val_t(alignemnt)) char[size]),
    ...
{
}

Hiç yorum yok:

Yorum Gönder