Вопрос по c++, g++, memory-alignment, powerpc, placement-new – Мне действительно нужно беспокоиться о выравнивании при использовании нового оператора размещения?

23

Я читал это Когда мне стоит беспокоиться о выравнивании? но я до сих пор не знаю, нужно ли мне беспокоиться о не выровненном указателе, возвращаемом оператором размещения new - как в этом примере:

class A {
public:
   long double a;
   long long b;
   A() : a(1.3), b(1234) {}
};

char buffer[64];

int main() {
   // (buffer + 1) used intentionally to have wrong alignment
   A* a = new (buffer + 1) A(); 
   a->~A();
}

__alignof(A) == 4, (buffer + 1) не выровнен с4. Но все работает отлично - полный пример здесь:http: //ideone.com/jBrk

Если это зависит от архитектуры, то я использую: linux / powerpc / g ++ 4.x.x.

[ОБНОВЛЕНИЕ] Сразу после публикации этого вопроса я прочитал эту статью:http: //virtrev.blogspot.de/2010/09/memory-alignment-theory-and-c-examples.htm. Может быть, единственным недостатком в моем случае было бы снижение производительности, я имею в виду стоимость выравниваемого доступа больше, чем выравнивание?

Place new просто возвращает указатель как дано. R. Martinho Fernandes
@ R.MartinhoFernandes, он также вызывает конструктор, который в этом случае устанавливает некоторые элементы. Если есть проблема этодолже вызвать его. Mark Ransom
@ FatalError, с сегодняшними архитектурами кэша я не уверен, что это правда больше. Конечно, вы увидите попадание, если пересечете границу строки кэша. Mark Ransom
x86 особенно прощает проблемы с выравниванием, powerpc не так уж и много. Mark Ransom
Неназначенные обращения часто поддерживается, но медленно. Это относится к x86, но я не знаю, для PPC. FatalError

Ваш Ответ

5   ответов
4

sparc), другим будет все равно, другие будут медленными. C ++ предполагает, что вы знаете, что делаете (или нет), так же, как reinterpret_cast и т. Д.

3

что gcc на powerpc имеет опцию, чтобы сообщить компилятору, обрабатывается ли система невыровненным доступом или нет.

Я бы предположил, что в любом случае доступ по выравниванию на этой платформе будет очень медленным, и его следует избегать, насколько это возможно.

19

Когда вы называете размещение новым в буфере:

A *a = new (buf) A;

Вы вызываете встроенноеvoid* operator new (std::size_t size, void* ptr) noexcept как определено в:

C ++ 11

18.6.1.3 Формы размещения [new.delete.placement]

Эти функции зарезервированы, программа на C ++ может не определять функции, которые заменяют версии в стандартной библиотеке C ++ (17.6.4). Положения (3.7.4) не применяются к этим зарезервированным формам размещения операторов new и operator delete.

void* operator new(std::size_t size, void* ptr) noexcept;
Возвращается:ptr.
Замечания: Преднамеренно не выполняет никаких других действий.

The положения о (3.7.4) включить, что возвращаемый указатель должен быть соответствующим образом выровнен, так что это хорошо дляvoid* operator new (std::size_t size, void* ptr) noexcept чтобы вернуть не выровненный указатель, если он передан. Это не позволяетт сорваться с крючка, хотя:

5.3.4 Новый [expr.new]

[14] Примечание: когда функция выделения возвращает значение, отличное от нуля, это должен быть указатель на блок хранения, в котором зарезервировано пространство для объекта. Предполагается, что блок хранения выровнен соответствующим образом и имеет запрошенный разме

Так что, если вы передаете невыровненное хранилище выражению с новым размещением, вы нарушаете предположение, что хранилище выровнено, и в результате получается UB.

Indeed, в вашей программе выше, если вы заменитеlong long b с__m128 b (после#include <xmmintrin.h>) тогда программа будет зависать, как и ожидалось.

так что это значит? Означает ли это, что мы должны передать на размещение новый адрес буфера + смещение, где (буфер + смещение)% выравнивания класса == 0? bysreg
@ bysreg уверен, что это сработает, если вы убедитесь, что свободного места достаточно. Или вы можете использовать средство, предоставляющее буфер, который уже выровнен, например, align_storage или posix_memalign. ecatmur
4

все зависит от архитектуры и, возможно, от флагов оптимизации компилятора. Все будет работать нормально, пока вы не сделаетеA b = a; или другой случайный доступ, который компилируется в некоторыйmovdqa ops, и ваша программа падает.

@ PiotrNycz: надеюсь, ты сможешь сохранить эту серию в живых ... Keith Randall
Я добавилA b = *a; к моему примеру, и это все еще работает. PiotrNycz
10

что все работает, не значит, что этона самом дел делает.

C ++ - это спецификация, которая определяет, что такоеобязательны работать. Компилятор также может заставить работать ненужные вещи. Вот что означает «неопределенное поведение»: все может произойти, поэтому ваш код больше не переносим.

С ++ не Требуют это на работу. Так что, если вы берете свой код в компилятор, где это не работает, вы больше не можете винить C ++; это ваша вина за неправильное использование языка.

C ++ 11 § 3.11 \ 2 «Типы объектов имеют требования к выравниванию (3.9.1, 3.9.2), которые накладывают ограничения на адреса, по которым может быть выделен объект этого типа». и § 3.11 \ 8 «Если запрос на конкретное расширенное выравнивание в конкретном контексте не поддерживается реализацией, программа является некорректной. Кроме того, запрос на выделение динамической памяти во время выполнения, для которого не может быть выполнено запрошенное выравнивание должны рассматриваться как сбой при распределении. " Mooing Duck
Вы имеете в виду, что использование не выровненного указателя при размещении new - это UB? Можете ли вы уточнить, какой стандарт говорит, что: C ++ 03 или C ++ 11? PiotrNycz

Похожие вопросы