Порядок хранения внутри структуры / объекта


Рассмотрим эти два случая:

struct customType
{
   dataType1 var1; 
   dataType2 var2;
   dataType3 var3;
} ;

customType instance1;
// Assume var1, var2 and var3 were initialized to some valid values.

customType * instance2 = &instance1;    
dataType1 firstMemberInsideStruct = (dataType1)(*instance2);

class CustomType
{
   public:
       dataType1 member1;
       dataType2 member2;

       retrunType1 memberFunction1();

   private:
       dataType3 member3;
       dataType4 member4;

       retrunType2 memberFunction2();
};

customType object;
// Assume member1, member2, member3 and member4 were initialized to some valid values.

customType *pointerToAnObject = &object ;
dataType1 firstMemberInTheObject = (dataType1) (*pointerToAnObject);

Всегда либезопасно это делать ?

Я хочу знать, определяет ли стандарт какой-либо порядок хранения среди -

  1. элементы внутри структуры С.
  2. члены данных внутри объекта класса C++.
2 3

2 ответа:

C99 и C++ немного отличаются в этом отношении.

Стандарт C99 гарантирует, что поля структуры будут располагаться в памяти в том порядке, в котором они объявлены, и что поля двух идентичных структур будут иметь одинаковые смещения. См. этот вопрос для соответствующих разделов стандарта С99. Подводя итог: смещение первого поля задается равным нулю, но смещения после этого не задаются стандартом. Это делается для того, чтобы компиляторы C могли корректировать смещения каждого поля таким образом, чтобы поле удовлетворяло любым требованиям к выравниванию памяти архитектуры. Поскольку это зависит от реализации, C предоставляет стандартный способ определения смещения каждого поля с помощью offsetof Макрон.

C++ предлагает эту гарантию только дляпростых старых данных (POD) . Классы C++, которые не являются простыми старыми данными, не могут быть обработаны подобным образом. Стандарт дает компилятору C++ довольно много свободы в том, как он организует класс, когда класс использует множественное наследование, имеет непубличные поля или члены или содержит виртуальные члены.

Что это означает для ваших примеров:

dataType1 firstMemberInsideStruct = (dataType1)(*instance2);

Эта строка подходит только в том случае, если dataType1, dataType2 и dataType3 являются обычными старыми данными. Если какой-либо из них отсутствует, то структура customType может не иметь тривиального конструктора (или деструктора), и это предположение может не выполняться.

dataType1 firstMemberInTheObject = (dataType1) (*pointerToAnObject);

Эта линия небезопасна независимо от того, является ли она безопасной.dataType1, dataType2, и dataType3 являются POD, потому что CustomType класс имеет частные переменные экземпляра. Это делает его не классом POD, и поэтому вы не можете предположить, что его переменная первого экземпляра будет упорядочена определенным образом.

9.0.7

Класс стандартной компоновки-это класс, который: - не имеет нестатических данных члены класса нестандартной компоновки типа (или массива таких типов) или ссылка, - не имеет виртуальных функций (10.3) и виртуальной базы классы (10.1), - имеет одинаковый контроль доступа (пункт 11) для всех нестатические члены данных, - не имеет нестандартной компоновки базовых классов, - либо не имеет нестатических членов данных в самом производном классе и на самый один базовый класс с нестатическими данными членов, или не имеет базы классы с нестатическими членами данных, и-не имеет базовых классов тот же тип, что и у первого нестатического элемента данных.108

9.2.14

Нестатические члены данных класса (не объединенного) с одинаковым доступом контроль (пункт 11) распределяются таким образом, чтобы более поздние члены имели более высокие адреса внутри объекта класса. Порядок выделения нестатических элементы данных с различным управлением доступом не указаны (11). Согласование реализации требования могут вызвать два соседних элемента не должны быть распределены сразу после друг друга; так могли бы требования к пространству для управления виртуальными функциями (10.3) и виртуальные базовые классы (10.1).

9.2.20

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