ПроблемаОператор, новый не перегруженный для возможно сверхвыровненного класса, происходит, когда вы не соответственно перегружаете оператор new/new[]
и вы используете этот оператор, чтобы создать объект с требованием выравнивания, заданным с alignas
. Средство проверки повышает дефект для этих версий броска и неброска оператора new/new[]
.
void* operator new(std::size_t size)
void* operator new(std::size_t size, const std::nothrow_t&)
void* operator new[](std::size_t size)
void* operator new[](std::size_t size, const std::nothrow_t&)
Использование alignas
указывает, что вы не ожидаете оператор по умолчанию new/new[]
удовлетворить требованию выравнивания или объекту, и что объект возможно по выровненному. Тип по выровненному, если вы используете alignas
сделать требование выравнивания типа больше, чем std::max_align_t
. Например, foo
по выровненному в этом фрагменте кода, потому что его требование выравнивания составляет 32 байта, но std::max_align_t
имеет выравнивание 16 байтов в большинстве реализаций.
struct alignas(32) foo {
char elems[32];
};
|
Оператор, новый не перегруженный для возможно сверхвыровненного класса, не повышает дефекта, если вы не перегружаете оператор new/new[]
и вы используете версию C++ 17 или позже Стандарта. Оператор по умолчанию new/new[]
на C++ 17 или более поздние поддержки по выравниванию путем передачи требования выравнивания в качестве аргумента типа std::align_val_t
, например, void* operator new(std::size_t size, std::align_val_t alignment)
.
РискОператор по умолчанию new/new[]
выделяет устройство хранения данных с требованием выравнивания std::align_val_t
самое большее. Если вы не перегружаете оператор, когда вы создаете объект с по выровненному типу, полученный объект может быть неправильно выровнен. Доступ к этой объектной силе вызывает ошибки несанкционированного доступа или аварийные завершения программы.
ФиксацияЕсли вы используете версию C++ 14 или ранее Стандарта, передаете требование выравнивания по выровненным типам к оператору new/new[]
путем перегрузки оператора.
Пример - выделенная память меньше, чем требование выравнивания типа foo
#include <new>
#include <cstdlib>
#include <iostream>
struct alignas(64) foo {
char elems[32];
};
foo* func()
{
foo* bar = 0x0;
try {
bar = new foo ;
} catch (...) { return nullptr; }
delete bar;
}
В этом примере, структура foo
объявляется с требованием выравнивания 32 байтов. Когда вы используете оператор по умолчанию new
создать объект bar
, выделенная память для bar
меньше, чем требование выравнивания типа foo
и bar
может быть неправильно выровнен.
Коррекция — задает перегруженный оператор new
обрабатывать требование выравнивания типа foo
Одна возможная коррекция, если вы используете C11 stdlib.h
или POSIX-C malloc.h
, должен задать перегруженный оператор new
это использует aligned_alloc()
или posix_memalign()
или получить устройство хранения данных с правильным выравниванием.
#include <new>
#include <cstdlib>
#include <iostream>
struct alignas(64) foo {
char elems[32];
static void* operator new (size_t nbytes)
{
if (void* p =
::aligned_alloc(alignof(foo), nbytes)) {
return p;
}
throw std::bad_alloc();
}
static void operator delete(void *p) {
free(p);
}
};
foo* func()
{
foo* bar = 0x0;
try {
bar = new foo ;
} catch (...) { return nullptr; }
delete bar;
}