Порядок хранения внутри структуры / объекта
Рассмотрим эти два случая:
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);
Всегда либезопасно это делать ?
Я хочу знать, определяет ли стандарт какой-либо порядок хранения среди -
- элементы внутри структуры С.
- члены данных внутри объекта класса C++.
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, указывает на его начальный элемент (или если этот элемент является бит-поле, затем к единице, в которой оно находится) и наоборот. [ Примечание: следовательно, могут быть безымянный обивка внутри стандарт-макет структурирует объект, но не в его начале, как это необходимо для достижения соответствующего выравнивания. - Конечная нота]