Выравнивание класса по классу, от которого он наследуется? Принудительно выравнивать все стеки? Изменить размер?
Я хочу иметь базовый класс, который диктует выравнивание объектов, которые наследуются от него. Это прекрасно работает для кучи, потому что я могу контролировать, как это распределяется, и как массивы распределяются в шаблоне пользовательского массива. Тем не менее, фактический размер класса для C++ не меняется вообще. То есть, если я выполню арифметику с указателем над указателем производного класса, он будет пропущен в неправильном месте. Это проблема первая.
Вторая проблема - выравнивание стека. Кажется, не существует способа напрямую заставить весь стек быть 16-байтовыми указателями.
Единственное, на что я могу повлиять - это специфические настройки компилятора vC++ и g++, но проблема здесь в том, что мне не нужно постоянно исправлять выравнивание вручную. Это должно быть подвержено ошибкам, не говоря уже о боли.
Я мог бы также сделать какой-нибудь умный указатель, но это также привело бы к появлению новых проблем.
Если я просто выровняю базовый класс, будут ли выровнены и дочерние классы? Если так, это решило бы большинство моих проблем, но это кажется сомнительным (хотя я попробую это).
3 ответа
Если базовый класс имеет определенное требование выравнивания, то любые производные классы будут иметь по крайней мере такое выравнивание (они могут получить более строгое требование выравнивания из-за своих собственных членов). В противном случае компилятор не может гарантировать, что доступ к базовым элементам будет соответствовать их требованиям.
Тем не менее, на самом деле вы ничего не можете сделать для выравнивания стека - это полностью обрабатывается компилятором и требованиями ABI платформы компилятора. Как вы указываете, опция компилятора или, возможно, прагма может позволить вам осуществлять некоторый контроль, но ничего переносимого.
Помня ответ Михаэля относительно переносимости... Я предполагаю, что вы нацелены на векторизацию SSE и начинаете чувствовать эту боль, и это действительно должно быть стандартным способом сделать это с явными подсказками и контролем низкого уровня. Оба компилятора, о которых вы упомянули, по умолчанию стремятся к 16-байтовому выравниванию в стеке.
Таким образом, хотя поддержка компиляторов может быть различной, может быть изменена, подвергнута сомнению и т. Д., Она также может быть недостаточно использована для одного из них; это зависит от используемых вами оптимизаторов и типов и, естественно, от выбора векторизатора для здравомыслия. Опять же, неясно, что вы делаете и в чем польза.
Так как определение вашей проблемы без примера схематично, возможно, вы можете дать команду declspec(align(16)) для Калифорнии (с LTCG) и __attribute ((align (16))) для gcc. Если это поможет, было бы хорошо сообщить нам, и что конкретно работает или нет в примере, какие предупреждения или ошибки компилятора тоже. Я бы также избегал использования умных указателей по разным причинам.
sizeof в вашем вопросе означает, что вы также сталкиваетесь с проблемами, связанными с массивами переменных и типами указателей, и в этом случае первое может быть проблематичным. И даже если вы можете потерять конструктор копирования и средства назначения, проверка машинного кода не повредит. То есть, в случае осложнений, вам нужно взглянуть на вывод и в случае переключения VC++ на Intel для лучшей подсказки в Windows, а также проверить /compilet и ошибки assert/trap во время выполнения на раннем этапе или для другого выбора любой бесплатный инструмент для анализа объектных файлов. Тогда вы просто работаете с явно проблемными конструкциями самым разумным образом, что всегда возможно.
У нас была похожая проблема на PARISC HPUX, где единственной атомарной конструкцией была 4-байтовая атомарная очистка, которая требовала выравнивания 16 байт.
Мы могли бы выдумать это, объявив наше 4-байтовое количество следующим образом:
struct Stupid_HPUX { int 4byteLockWordInHere [4]; };
и выбрать правильный для использования во время выполнения. Для вашей проблемы, вы могли бы сделать что-то подобное
союз rawMemory { int blah[(sizeof(yourtype) + 16)/4]; символ с [1]; } у;
затем используйте новое размещение с адресом, определенным во время выполнения, чтобы исправить требуемое местоположение.