В Как использовать выравнивание для выравнивания силы для выделения кучи? , Я спросил, как использовать alignof
для объектов, выделенных кучей. Теперь я обобщаю свой вопрос для любого способа принудительного выравнивания объектов, выделенных кучей, потому что я не могу найти способ сделать это с помощью alignof
, std::aligned_storage
или std::align
. Следующий код компилируется, но ни VC12, ни Clang 3.2 не производят последовательность нулей в качестве вывода, которая указывает, что мой запрос выравнивания соблюдается. (gcc 4.8.1 не хватает std::align
, но если вы прокомментируете эту часть, код компилируется под gcc 4.8.1, а также выводит вывод, указывающий, что мои запросы выравнивания игнорируются.)
#include <iostream>
#include <memory>
int main()
{
// Try using alignas on the allocation
{
class Widget {};
for (int i = 0; i < 5; ++i)
{
auto ptr = new alignas(64) Widget;
std::cout << (long)ptr % 64 << '\n'; // should be 0
}
}
// Try using alignas on the type
{
class alignas(64) Widget {};
for (int i = 0; i < 5; ++i)
{
auto ptr = new Widget;
std::cout << (long)ptr % 64 << '\n'; // should be 0
}
}
// Try using std::aligned_storage
{
class Widget {};
using WidgetStorage_t =
std::aligned_storage<sizeof(Widget), 64>::type;
for (int i = 0; i < 5; ++i)
{
auto ptr = new WidgetStorage_t; // get buffer
new (ptr) Widget; // construct Widget
std::cout << (long)ptr % 64 << '\n'; // should be 0
}
}
// Try using operator new + std::align
{
class Widget {};
for (int i = 0; i < 5; ++i)
{
auto requestSize = // double space to ensure that a
2 * sizeof(Widget); // Widget fits after ptr adjustment
auto ptr = operator new(requestSize); // get buffer
std::align(64, sizeof(Widget), // align ptr
ptr, requestSize); // inside buffer
new (ptr) Widget; // construct Widget
std::cout << (long)ptr % 64 << '\n'; // should be 0
}
}
}
UPDATE: мой код для тестирования std::align
неверно. Следующий код замены работает:
// Try using operator new + std::align
{
class Widget {};
for (int i = 0; i < 5; ++i)
{
auto requestSize = // ensure that a
sizeof(Widget) + 64; // Widget fits after ptr adjustment
auto ptr = operator new(requestSize); // get buffer
std::align(64, sizeof(Widget), // align ptr
ptr, requestSize); // inside buffer
new (ptr) Widget; // construct Widget
std::cout << (long)ptr % 64 << '\n'; // should be 0
}
}
Это единственный способ получить работу? Это намного сложнее, чем хотелось бы, потому что теперь нужно отслеживать два указателя: скорректированный, который указывает на объект (необходимый для уничтожения построенного объекта) и нескорректированный, который указывает на буфер памяти (необходимый для освобождения память).
Один из вариантов, который я видел на практике, это перераспределение, а затем выравнивание вещей для себя.
Например, предположим, что вы хотите выделить N байтов, согласованных с границами байтов M. Вы можете продолжить, выделив N + M-1 байт, а затем найдите первый согласованный по M-байту адрес в выделенном пространстве. Например, вы можете сделать что-то вроде:
const size_t N = sizeof(Widget);
const size_t M = 64;
char *pc = new char[N+M-1];
char *pc_aligned = (pc+M-1)&(~(M-1));
Widget *p = new (pc_aligned) Widget(); // placement new
// ...
p->~Widget(); // explicitly call destructor
delete [] pc; // delete array allocated with new
std::align
.
std::align
прямо сейчас.
MS четко документирует, что С++ 11 alignas
по адресу http://msdn.microsoft.com/en-us/library/hh567368.aspx
Для GNU - кажется, он работает, если вы положили его в нужное место - откуда я могу использовать alignas() в С++ 11? просто вкус - см. этот ответ для многих других примеров и обсуждений:
typedef float aligned_block alignas(16) [4];
typedef float aligned_block [4] alignas(16);
new
должен учитывать это вплоть до alignof(std::max_align_t)
, после которого «Если выравнивание, связанное с конкретным переопределенным типом, не поддерживается распределителем , создание экземпляра распределителя для этого типа может завершиться неудачей. Распределитель также может молча игнорировать запрошенное выравнивание. ", что в основном означает, что вы вернулись к его организации вручную согласно ответу SchighSchagh. Суть этого ответа заключается в описании поддержки компилятора и нотации для alignas
.
class alignas(64) Widget {};
?Widget
имеют 64-байтовое выравнивание, хотя, похоже, это не имеет никакого эффекта для объектов кучи. Пустые фигурные скобки - это тело класса. Для этого примера мне все равно, что в классе.