К сожалению, обеспечение максимального выравнивания намного сложнее, чем должно быть, и нет никаких гарантированных решений, насколько я знаю. Из блога GotW (Статья Fast Pimpl):
union max_align {
short dummy0;
long dummy1;
double dummy2;
long double dummy3;
void* dummy4;
/*...and pointers to functions, pointers to
member functions, pointers to member data,
pointers to classes, eye of newt, ...*/
};
union {
max_align m;
char x_[sizeofx];
};
Это не гарантирует полной переносимости, но на практике это достаточно близко, потому что мало или совсем нет систем, на которых это не будет работать должным образом.
Это самый близкий «взлом», который я знаю для этого.
Есть еще один подход, который я лично использовал для сверхбыстрого распределения. Обратите внимание, что это зло, но я работаю в области трассировки лучей, где скорость является одним из самых важных показателей качества, и мы ежедневно профилируем код. Он включает в себя использование распределителя кучи с предварительно выделенной памятью, который работает как локальный стек (просто увеличивает указатель при выделении и уменьшает его при освобождении).
Я использую его, в частности, для Pimpls. Однако просто иметь распределитель недостаточно; чтобы такой аллокатор работал, мы должны предположить, что память для класса Foo выделяется в конструкторе, та же самая память освобождается только в деструкторе, а сам Foo создается в стеке. Чтобы сделать это безопасным, мне нужна функция, чтобы увидеть, находится ли указатель this класса в локальном стеке, чтобы определить, можем ли мы использовать наш сверхбыстрый распределитель стека на основе кучи. Для этого нам пришлось исследовать решения для конкретной ОС: я использовал TIB и TEB для Win32/Win64, и мои коллеги нашли решения для Linux и Mac OS X.
В результате, после недели изучения специфичных для ОС методов для определения диапазона стека, требований к выравниванию, а также большого количества тестов и профилирования, стал распределитель, который мог выделять память за 4 такта в соответствии с нашими тестами счетчика тиков, в отличие от примерно 400 циклов для malloc/operator new (наш тест включал конфликт потоков, поэтому malloc, вероятно, будет немного быстрее, чем это в однопоточных случаях, возможно, на пару сотен циклов). Мы добавили стек кучи для каждого потока и определили, какой поток используется, что увеличило время примерно до 12 циклов, хотя клиент может отслеживать распределитель потоков, чтобы получить выделение 4 циклов. Он стер с карты точки доступа, основанные на распределении памяти.
Хотя вам не нужно преодолевать все эти проблемы, написание быстрого распределителя может быть проще и более применимо (например, позволяет определять объем памяти для выделения/освобождения во время выполнения), чем что-то вроде max_align
здесь. max_align
достаточно прост в использовании, но если вам нужна скорость для выделения памяти (и если вы уже профилировали свой код и нашли горячие точки в malloc/free/operator new/delete с основными вкладчиками, находящимися в коде, который вы контролируете) , написание собственного распределителя действительно может иметь значение.
person
stinky472
schedule
27.06.2010
Align
дляstd::aligned_storage<Len, Align>
имеет аргумент по умолчанию default-alignment, который определяется как Значение default-alignment должно быть самым строгим требованием выравнивания для любого типа объекта C++, размер которого не превышаетLen
. Я не знаю, считаются ли типы SSE типами объектов C++, а в стандартной библиотеке VC10 нет аргумента по умолчанию, поэтому я не знаю, каково предполагаемое значение (у меня нет других реализаций стандартной библиотеки на эта машина). - person James McNellis   schedule 30.12.2010