2013-04-12 3 views
0

В общей ситуации структуры/класса может существовать выравнивание между членами. Но мне интересно, будет ли это с уверенностью предположить, что это особый случай:Выравнивание после элемента массива того же типа

template<typename T, size_t N> 
struct MyStruct { 
    T data[N]; 
    T term; 
    constexpr MyStruct(); 
}; 

будет надежно эквивалент этого:

template<typename T, size_t N> 
struct MyStruct { 
    T data[N+1]; 
    constexpr MyStruct(); 
}; 

Причина спрашиваю, что я на самом деле хочу, чтобы быть в состоянии явно инициализировать последний элемент массива в конструкторе constexpr (но мне все равно, что остальное). Например, с верхней MyStruct я могу это сделать:

template<typename T, size_t N> 
constexpr MyStruct<T,N>::MyStruct() : data{}, term{0} {} 

Но я хочу, чтобы результат такой же, как если бы срок был действительно последний элемент массива.

Безопасно ли это? Если нет, есть ли способ достичь того же, используя вторую форму MyStruct?

+1

В соответствии с §5.3.6 массив и тип имеют одинаковое выравнивание, поэтому не должно быть никаких отступов. Но в §9.2 говорится: «[..] Требования к выравниванию реализации могут привести к тому, что сразу два соседних элемента не будут распределены сразу после друг друга, поэтому могут потребоваться требования к пространству для управления виртуальными функциями (10.3) и виртуальными базовыми классами (10.1)». _ Может ли кто-нибудь построить случай, когда это не удается? – 2013-04-12 14:53:51

+0

Спасибо, это полезно. Я пробовал различные эксперименты с gcc и еще не нашел сбой. Я играю только с простыми структурами, мой текущий вариант использования не потребует виртуальных типов. – GeoffW

+1

У меня возникло бы желание использовать 'union' и, по крайней мере, сделать математику размера' static_assert'. И некоторую математику 'assert', чтобы убедиться, что' & two.last == & one.arr [N-1] '. – Yakk

ответ

0

Это небезопасно для Предположим, никакого промежутка между вашими данными [N] и переменной вашего члена. Например, вы можете явно контролировать, как компилятор Microsoft выравнивает переменные с n-байтовыми границами (где n равно 1, 2, 4, 8 или 16), см. http://msdn.microsoft.com/en-us/library/xh3e3fd0(v=vs.80).aspx.

+0

Связанная статья гласит: «Когда вы укажете эту опцию, каждый член структуры после первого сохраняется либо размером размера члена, либо n-байтовыми границами (где n равно 1, 2, 4, 8 или 16), * * в зависимости от того, что меньше **. " Поэтому мне кажется, что компилятор все же может выбрать согласование похожих типов вместе - действительно, этот оператор, похоже, предположил бы, что я в безопасности (учитывая, что данные [N] и термин имеют один и тот же тип, как описано выше). – GeoffW

+0

Конечно, если вы можете свободно выбирать/Zp1 с компилятором Microsoft, тогда все будет в порядке. Но если вы пишете код, который может использоваться во многих компиляторах, то вы определенно не в порядке, и даже с Microsoft может получиться, что/Zp1 конфликтует с чем-то другим, что вы делаете. Мое предложение было бы попытаться найти другой путь, и тогда вам не нужно беспокоиться об этом. По моему опыту, эти проблемы низкого уровня всегда возвращаются и в конце концов укусят вас! – Stochastically

+0

Обратите внимание, что «в зависимости от того, что меньше» относится к выбору между размером элемента и выравниванием - поэтому переключатель/Zp не имеет значения. Символ все еще выравнивается в 1 (без интервала, потому что массив закончен на этой границе), слово в 2 и т. Д. Если T оказывается какой-то нечетной структурой по сравнению с размером выравнивания, все становится сложнее в разработке, хотя, похоже, все в порядке. Но я действительно говорю о проблемах с низким уровнем, возвращающихся к укусу. – GeoffW

Смежные вопросы