Динамическое выравнивание памяти в C ++ 11 - PullRequest
38 голосов
/ 07 августа 2011

posix_memalign и _aligned_malloc в Windows позволяют динамически выделять выровненный фрагмент памяти. Есть ли что-нибудь подобное в C ++ 11? Насколько я знаю, ключевое слово alignas работает только со статически размещенными объектами.

Ответы [ 7 ]

28 голосов
/ 12 мая 2013

Это зависит от того, какое выравнивание вам требуется.Для всего <= to <code>alignof(std::max_align_t), new работает согласно n3242 3.7.4.1/2:

Возвращаемый указатель должен быть соответствующим образом выровнен, чтобы его можно было преобразовать в указатель любого полноготип объекта с требованием фундаментального выравнивания

std::max_align_t - это полный тип объекта с самым строгим фундаментальным выравниванием.

Обратите внимание, что выделение массивов char или unsigned char, ноnot signed char имеют другое правило в 5.3.4 / 10:

Для массивов char и unsigned char, разница между результатом выражения new и адресом, возвращаемым функцией распределениядолжно быть целым кратным самого строгого требования фундаментального выравнивания (3.11) любого типа объекта, размер которого не превышает размер создаваемого массива.

Так что new char[1]; может иметь выравнивание1.

Что касается выделения памяти с выравниванием, превышающим alignof(std::max_align_t), C ++ 11 не предоставляет прямого способа сделать это.Единственный надежный способ - выделить как минимум size + alignment байтов и использовать std :: align для получения правильно выровненного расположения в этом буфере.

Это может привести к потере большого количества памяти, поэтомуесли вам нужно их много, вы можете создать распределитель, который выделит достаточно большой кусок для всех них, и использовать для этого std :: align.Затем ваши накладные расходы амортизируются по всем выделениям.

Другой вариант - дождаться http://open -std.org / JTC1 / SC22 / WG21 / docs / paper / 2012 / n3396.htm, чтобы превратить его в стандарт.

Лично я бы просто написал слой абстракции поверх API, предоставляемых ОС для выделения выровненной памяти.

9 голосов
/ 07 августа 2011

Вы можете использовать posix_memalign / _aligned_malloc, чтобы выделить часть памяти, а затем использовать специальный синтаксис оператора «new» для инициализации объекта в этой области памяти.Как то так:

// Allocate raw memory for a Foo object.
void *mem;
size_t alignment = 0x1000;
size_t size = ?;
posix_memalign(&mem, alignment, size);
// Call the constructor on the allocated memory.
Foo *foo = new (mem) Foo(...);

// Now you have a useable object.
foo->some_method();

// Call destructor without freeing object memory.
foo->~Foo();
// Free raw memory.
free(foo);
5 голосов
/ 15 июня 2012

Посмотрите на std::aligned_storage и оператор alignas(). Они являются частью C ++ 11 и, похоже, именно то, что вы ищете.

5 голосов
/ 07 августа 2011

C ++ 03 и C ++ 0x имеют operator new.

new T или new T[] гарантирует возврат правильно выровненной памяти для объекта типа T.

new char[], new signed char[] и new unsigned char[] гарантируют возвращение памяти, правильно выровненной для любого объекта, так что вы можете использовать новое размещение на нем.

1 голос
/ 10 октября 2013

Для выровненной памяти, выделенной в куче, я использую реализацию align () из http://code.google.com/p/c-plus/source/browse/src/util.h#57,, потому что мой gcc4.8, похоже, не поддерживает его.Вот пример кода:

typedef float TItem;
static const int SIZE = 100;
static const int ALIGNMENT = 16;

// allocate heap storage larger then SIZE
TItem* storage = new TItem[SIZE + (ALIGNMENT / sizeof(TItem))];
void* storage_ptr = (void*)storage;
size_t storage_size = sizeof(TItem) * (SIZE + 1);
// aligned_array should be properly aligned
TItem* aligned_array = (TItem*) align(MEM_ALIGNMENT, sizeof(TItem) * SIZE, storage_ptr, storage_size);
if (!aligned_array) { throw std::bad_alloc(); }
0 голосов
/ 16 мая 2014

Intel TBB предоставляет портативный cache_aligned_allocator, который, я думаю, вы можете быть тем, что вы ищете.

0 голосов
/ 07 августа 2011

Стандарт C ++ всегда гарантировал подходящее выравнивание для любого объекта из выделений кучи, то есть

template<typename T> T* func() {
    char* buf = new char[sizeof(T)];
    return new(buf) T();
}

гарантированно не завершится с ошибкой по причинам выравнивания.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...