本文介绍了的std ::对齐和std :: aligned_storage的内存块的排列分配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图来分配大小的内存块尺寸这就需要将对齐对准哪里大小可能无法在编译时进行定义。我知道套路,如 _aligned_alloc posix_memalign _mm_alloc ,等存在,但我不希望使用他们,因为他们打倒code便携性。
C ++ 11 给出了一个常规的的std ::对齐键,也是一类的std :: aligned_storage 从中我可以检索一个POD类型来分配,这将对准我的要求的元素。但是我的目标是创建一个allocator这将拨出尺寸大小的内存块(不只是一个单一的元素),这将保持一致。
使用的std ::对齐这可能吗?我想问的原因是因为的std ::调整移动指针,使用该指针将会给分配一个指针移到地址释放这将是无效的类。有没有一种方法来创建一个aligned_allocator这种方式?

I'm trying to allocate a block of memory of size size which needs to be Alignment aligned where the size may not be defined at compile time. I know routines such as _aligned_alloc, posix_memalign, _mm_alloc, etc exist but I do not want to use them as they bring down code portability.
C++11 gives a routine std::align and also a class std::aligned_storage from which I can retrieve a POD type to allocate an element which will be aligned to my requirements. However my goal is to create an allocator which would allocate a block of memory of size size (not just a single element) which would be aligned.
Is this possible using std::align? The reason I ask is since std::align moves the pointer, the class using that pointer will give the allocator a pointer to the moved address for deallocation which would be invalid. Is there a way to create an aligned_allocator this way?

推荐答案

编辑:从OP澄清后,它将出现在原来的答案是题外话;为参考起见它被保持在该答案的末端。

after clarifications from the OP, it appears the original answer is off-topic; for reference's sake it is kept at the end of this answer.

其实,答案很简单:你只需要保持一个指针既能存储块和第一项

Actually, the answer is rather simple: you simply need to keep a pointer both to the storage block and to the first item.

这不,实际上,需要一个有状态的分配器(也可能是可能的,即使在C ++ 03,尽管有一个自定义的的std ::对齐常规)。诀窍是,不要求分配只要求系统完全足够的内存来存储用户数据。它可以完美地问多一点为自己的簿记目的。

This does not, actually, requires a stateful allocator (it could be possible even in C++03, albeit with a custom std::align routine). The trick is that the allocator is not required to only ask of the system exactly enough memory to store user data. It can perfectly ask a bit more for book-keeping purposes of its own.

所以,在这里我们去创造一个对齐分配;保持简单,我会集中在分配/释放例程。

So, here we go creating an aligned allocator; to keep it simple I'll focus on the allocation/deallocation routines.

template <typename T>
class aligned_allocator {
    // Allocates block of memory:
    // - (opt) padding
    // - offset: ptrdiff_t
    // - T * n: T
    // - (opt) padding
public:
    typedef T* pointer;
    typedef size_t size_type;

    pointer allocate(size_type n);
    void deallocate(pointer p, size_type n);

}; // class aligned_allocator

而现在的分配程序。大量内存摆弄,这毕竟分配器的心脏!

And now the allocation routine. Lots of memory fiddling, it's the heart of the allocator after all!

template <typename T>
auto aligned_allocator<T>::allocate(size_type n) -> pointer {
    size_type const alignment = std::max(alignof(ptrdiff_t), alignof(T));
    size_type const size = sizeof(ptrdiff_t) + sizeof(T)*n + alignment;

    // block is correctly aligned for `ptrdiff_t` because `std::malloc` returns
    // memory correctly aligned for all built-ins types.
    void* const block = std::malloc(size);

    if (block == nullptr) { throw std::bad_alloc{}; }

    // find the start of the body by suitably aligning memory,
    // note that we reserve sufficient space for the header beforehand
    void* storage = reinterpret_cast<char*>(block) + sizeof(ptrdiff_t);
    size_t shift = 0;

    void* const body = std::align(alignment, size, storage, shift);

    // reverse track to find where the offset field starts
    char* const offset = reinterpret_cast<char*>(body) - sizeof(ptrdiff_t);

    // store the value of the offset (ie, the result of body - block)
    *reinterpret_cast<ptrdiff_t*>(offset) = sizeof(ptrdiff_t) + shift;

    // finally return the start of the body
    return reinterpret_cast<ptrdiff_t>(body);
} // aligned_allocator<T>::allocate

幸运的是,释放程序要简单得多,它只是读取偏移和应用它。

Fortunately the deallocation routine is much simpler, it just has to read the offset and apply it.

template <typename T>
void aligned_allocator<T>::deallocate(pointer p, size_type) {
    // find the offset field
    char const* header = reinterpret_cast<char*>(p) - sizeof(ptrdiff_t);

    // read its value
    ptrdiff_t const offset = *reinterpret_cast<ptrdiff_t*>(header);

    // apply it to find start of block
    void* const block = reinterpret_cast<char*>(p) - offset;

    // finally deallocate
    std::free(block);
} // aligned_allocator<T>::deallocate

其他的程序不需要知道的内存布局,所以写这些是微不足道的。

The other routines need not be aware of the memory layout, so writing them is trivial.

原来的答复:

template <typename T>
class Block {
public:
    Block(Block const&) = delete;
    Block& operator=(Block const&) = delete;

    explicit Block(size_t n);
    ~Block();

private:
    void* _storage;
    T* _begin;
    T* _end;
}; // class Block

template <typename T>
Block<T>::Block(size_t n) {
    size_t const size = n * sizeof(T) + alignof(T);

    _storage = std::malloc(size);

    void* stock = _storage;
    size_t dummy = 0;
    std::align(alignof(T), size, stock, dummy);

    _begin = _end = reinterpret_cast<T*>(stock);
} // Block<T>::Block

template <typename T>
Block<T>::~Block() {
    for (; _end != _begin; --_end) {
        (_end - 1)->~T();
    }

    std::free(_storage);
} // Block<T>::~Block

这篇关于的std ::对齐和std :: aligned_storage的内存块的排列分配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-31 00:15