Мой вопрос довольно прост;
Работает ли спецификатор alignas с ‘new’? То есть, если структура определена для выравнивания, будет ли она выравниваться при выделении с новым?
Если выравнивание вашего типа не выровнено, то да, по умолчанию new
буду работать. «Выровненный» означает, что выравнивание, указанное вами в alignas
больше, чем alignof(std::max_align_t)
, По умолчанию new
будет работать с не выровненными типами более или менее случайно; Распределитель памяти по умолчанию всегда будет выделять память с выравниванием, равным alignof(std::max_align_t)
,
Если выравнивание вашего типа слишком выровнено, вам не повезло. Ни по умолчанию new
ни какой глобальный new
Оператор, которого вы напишете, сможет даже узнать требуемое выравнивание типа, не говоря уже о выделении памяти, соответствующей ему. Единственный способ помочь в этом случае — перегрузить класс operator new
, который сможет запросить выравнивание класса с alignof
,
Конечно, это не будет полезно, если этот класс используется как член другого класса. Нет, если этот другой класс также не перегружен operator new
, Так просто new pair<over_aligned, int>()
не сработает
Предложение для C ++ 17 (которое было принято) добавляет поддержка динамического выделения выровненных типов, имея перегрузки operator new/delete
что взять alignof
типа выделяется. Это также будет поддерживать выравнивания меньше максимального выровненного типа, поэтому ваш распределитель памяти не всегда должен возвращать память, выровненную по alignof(std::max_align_t)
,
Это, как говорится, компиляторы не требуется поддерживать перегруженные типы на всех.
Нет. Структура будет дополнена запрошенным выравниванием, но она не будет выровнена. Однако есть вероятность, что это будет разрешено в C ++ 17 (Тот факт, что это предложение C ++ 17 существует, должно быть довольно хорошим доказательством того, что это не может работать в C ++ 11).
Я видел, как это работает с некоторыми распределителями памяти, но это была чистая удача. Например, некоторые распределители памяти будут выравнивать свои выделения памяти в степени 2 запрошенного размера (до 4 КБ) в качестве оптимизации для распределителя (уменьшить фрагментацию памяти, возможно, упростить повторное использование ранее освобожденной памяти и т. Д.) , Однако новые реализации / malloc, которые включены в системы OS X 10.7 и CentOS 6, которые я тестировал, не делают этого и терпят неудачу со следующим кодом:
#include <stdlib.h>
#include <assert.h>
struct alignas(8) test_struct_8 { char data; };
struct alignas(16) test_struct_16 { char data; };
struct alignas(32) test_struct_32 { char data; };
struct alignas(64) test_struct_64 { char data; };
struct alignas(128) test_struct_128 { char data; };
struct alignas(256) test_struct_256 { char data; };
struct alignas(512) test_struct_512 { char data; };
int main() {
test_struct_8 *heap_8 = new test_struct_8;
test_struct_16 *heap_16 = new test_struct_16;
test_struct_32 *heap_32 = new test_struct_32;
test_struct_64 *heap_64 = new test_struct_64;
test_struct_128 *heap_128 = new test_struct_128;
test_struct_256 *heap_256 = new test_struct_256;
test_struct_512 *heap_512 = new test_struct_512;
#define IS_ALIGNED(addr,size) ((((size_t)(addr)) % (size)) == 0)
assert(IS_ALIGNED(heap_8, 8));
assert(IS_ALIGNED(heap_16, 16));
assert(IS_ALIGNED(heap_32, 32));
assert(IS_ALIGNED(heap_64, 64));
assert(IS_ALIGNED(heap_128, 128));
assert(IS_ALIGNED(heap_256, 256));
assert(IS_ALIGNED(heap_512, 512));
delete heap_8;
delete heap_16;
delete heap_32;
delete heap_64;
delete heap_128;
delete heap_256;
delete heap_512;
return 0;
}