Обратите внимание на новый язык для C++11 ниже
В C++03 есть язык, который делает это возможным, 9.2 [class.mem]/12 (выделено мной):
Нестатические элементы данных (не объединенного) класса, объявленного без промежуточного спецификатора доступа, выделяются таким образом, чтобы более поздние члены имели более высокие адреса в объекте класса. Порядок размещения нестатических элементов данных, разделенных спецификатором доступа, не определен (11.1). Требования выравнивания реализации могут привести к тому, что два соседних элемента не будут выделены сразу друг за другом; так же как и требования к пространству для управления виртуальными функциями (10.3) и виртуальными базовыми классами (10.1).
Итак, учитывая это определение:
class Foo
{
char a; //8 bits
// a must come before b, so 3 bytes of padding have to go here to satisfy alignment
int b; //32 bits
char c; //8 bits
// 24 bits of padding required to make Foo a multiple of sizeof(int)
};
в системе с 32-битным (int
) выравниванием компилятору не разрешено переупорядочивать c
так, чтобы оно располагалось перед b
, заставляя вставлять дополнительные отступы между a
и b
и после c
до конца объекта (создавая sizeof(Foo) == 12
) . Однако для этого:
class Foo
{
char a;
public:
int b;
public:
char c;
};
a
и (b
и c
) разделены спецификатором доступа, поэтому компилятор может выполнять такое переупорядочение, что делает
memory-layout Foo
{
char a; // 8 bits
char c; // 8 bits
// 16 bits of padding
int b; // 32 bits
};
sizeof(Foo) == 8
.
В C++11 язык немного изменился. N3485 9.2 [class.mem]/13 говорит (выделено мной):
Нестатические элементы данных класса (не объединенного) с одинаковым контролем доступа (пункт 11) распределяются таким образом, чтобы более поздние члены имели более высокие адреса в объекте класса. Порядок размещения нестатических элементов данных с различным контролем доступа не определен (пункт 11). Требования выравнивания реализации могут привести к тому, что два соседних элемента не будут выделены сразу друг за другом; так же как и требования к пространству для управления виртуальными функциями (10.3) и виртуальными базовыми классами (10.1).
Это означает, что в C++11 в приведенном выше примере (разделенном тремя общедоступными) компилятору по-прежнему не разрешено выполнять переупорядочение. Это должно быть что-то вроде
class Foo
{
char a;
public:
int b;
protected:
char c;
};
, который размещает a
, b
и c
с разным контролем доступа.
Обратите внимание, что в соответствии с правилами С++ 11 при таком определении, как:
class Foo
{
char a;
public:
int b;
protected:
char c;
public:
int d;
};
компилятор должен поставить d
после b
, даже если они разделены спецификаторами доступа.
(Тем не менее, я не знаю ни одной реализации, которая действительно использует широту, предлагаемую любым стандартом)
person
Billy ONeal
schedule
05.07.2011