Подтвердить что ты не робот

Динамическое выделение выделенной памяти в С++ 11

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

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

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

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

Ответ 2

Вы можете использовать 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);

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

Для выровненной памяти, выделенной в куче, я использую реализацию 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(); }

Ответ 6

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

Ответ 7

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

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

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