3

Я хотел бы использовать 11 C++ std::aligned_alloc-х, но, к сожалению, он не доступен с Microsoft Visual Studio 2013.Что можно использовать вместо std :: aligned_alloc в MS Visual Studio 2013?

Я рассматриваю, intsead, реализуя aligned_alloc на мою собственную. Как должна выглядеть реализация? Следующие, например, не компилируются, потому что он не может конвертировать из void* в void*&.

template<typename T> 
T* aligned_alloc(std::size_t size, std::size_t align) 
{ 
     T* ptr = new T[size + align]; 
     std::align(align, size, reinterpret_cast<void*>(ptr), align + size); 
     return ptr; 
} 
+3

1) Не используйте 'new'. Это вызывает конструкторы. Используйте ':: operator new' для выделения памяти. Верните 'void *', не создавайте шаблон. 2) Вам нужно будет выделить дополнительную память для хранения исходного указателя, возвращаемого ':: operator new', чтобы впоследствии вы могли использовать его для освобождения. 3) Windows имеет '_aligned_malloc'. –

+0

В чем преимущество возврата void *? – user1235183

+1

'void *' дает понять, что вы возвращаете выделенное хранилище, а не построенные объекты. Это отдельные вещи, которые нужно обрабатывать отдельно. –

ответ

5

Отказ от ответственности: Я не полностью тестировал этот код.

void* aligned_alloc(std::size_t size, std::size_t alignment){ 
    if(alignment < alignof(void*)) { 
     alignment = alignof(void*); 
    } 
    std::size_t space = size + alignment - 1; 
    void* allocated_mem = ::operator new(space + sizeof(void*)); 
    void* aligned_mem = static_cast<void*>(static_cast<char*>(allocated_mem) + sizeof(void*)); 
    ////////////// #1 /////////////// 
    std::align(alignment, size, aligned_mem, space); 
    ////////////// #2 /////////////// 
    *(static_cast<void**>(aligned_mem) - 1) = allocated_mem; 
    ////////////// #3 /////////////// 
    return aligned_mem; 
} 

void aligned_free(void* p) noexcept { 
    ::operator delete(*(static_cast<void**>(p) - 1)); 
} 

Объяснение:

Выравнивание доводят до alignof(void*) если это меньше, чем это, потому что, как мы увидим, нам нужно хранить (выровнены) void*.

Нам нужны size + alignment - 1 байт, чтобы гарантировать, что мы можем найти size байт блок- там с выравниванием по правому краю, плюс дополнительные sizeof(void*) байт для хранения указателя, возвращаемого ::operator new, так что мы можем освободить его позже.

Мы выделяем эту память ::operator new и сохраняем возвращенный указатель в allocated_mem. Затем мы добавляем sizeof(void*) байт в allocated_mem и сохраняем результат в aligned_mem. На данный момент мы еще не выровняли его.

В точке # 1, блок памяти и две точки выглядеть следующим образом:

   aligned_mem (not actually aligned yet) 
       V 
+-------------+-----------------------------------------+ 
|sizeof(void*)| size + alignment - 1 bytes   | 
+-------------+-----------------------------------------+ 
^ 
allocated_mem points here 

std::align вызова регулирует aligned_mem для получения желаемого выравнивания. В точке # 2, это теперь выглядит следующим образом:

     aligned_mem (correctly aligned now) 
         V 
+---------------------+---------------------------------+ 
| extra space   | at least size bytes   | 
+---------------------+---------------------------------+ 
^ 
allocated_mem points here 

Поскольку мы начали в sizeof(void*) байт мимо allocated_mem, «лишнее пространство», по крайней мере sizeof(void*) байт. Кроме того, aligned_mem правильно выровнен для void*, поэтому мы можем сохранить void* прямо перед ним. В точке № 3, блок памяти выглядит следующим образом

     aligned_mem (returned to caller) 
         V 
+---------------+-----+---------------------------------+ 
|    |^| at least size bytes   | 
+---------------+--+--+---------------------------------+ 
^     | 
allocated_mem  value of allocated_mem 
points here  stored here 

Как aligned_free, он просто читает указатель, хранящийся там, и передает его в ::operator delete.

+0

Я не понимаю. Почему бесплатная работа правильно? – user1235183

+0

Хотя я не уверен, почему вы это сделаете, когда обе функции уже существуют в Windows. – Robinson

+0

@ user1235183 'aligned_alloc' заставляет указатель, возвращаемый' :: operator new', прямо перед блоком памяти, на который указывает его возвращаемое значение. Тогда 'aligned_free' просто считывает этот указатель и передает его в' :: operator delete'. –

1

В Windows это _aligned_malloc и _aligned_free, которые могут быть найдены в malloc.h. Реализация std (alignof/alignas) находится в VS 2015. Это не доступно в 2013 году.