Как объекты хранятся в памяти в C++?

как объекты хранятся в памяти в C++?

для обычного класса, таких как

class Object
    {
public:
    int i1;
    int i2;
    char i3;
    int i4;
private:
    };

использование указателя объекта в качестве массива может использоваться для доступа к i1 следующим образом?

((Object*)&myObject)[0] === i1?

другие вопросы на SO, похоже, предполагают, что приведение структуры к указателю будет указывать на первый член для POD-типов. Как это отличается для классов с конструкторами, если вообще? Также каким образом это отличается для non-POD типы?

Edit:

в памяти, следовательно, вышеуказанный класс будет выложен следующим образом?

[i1 - 4bytes][i2 - 4bytes][i3 - 1byte][padding - 3bytes][i4 - 4bytes]

5 ответов


почти. Вы бросили на объект* и забыли взять адрес. Давайте переспросим следующим образом:

((int*)&myObject)[0] == i1

вы должны быть очень осторожны с такими предположениями. Поскольку вы определили структуру, это должно быть верно в любом компиляторе, с которым вы, вероятно, столкнетесь. Но все виды других свойств объекта (которые вы, возможно, опустили в своем примере), как говорили другие, сделают его не-POD и могут (возможно, зависящим от компилятора способом) сделать вышеизложенное утверждение неверно.

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

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


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

когда у вас есть виртуальные члены, у них есть" vtable " в памяти, которая содержит указатели на фактическую функцию, которая создается на основе иерархии наследования класс.

суть в следующем: не получить доступ к классам таким образом, если вы можете избежать этого (а также не memset их или memcpy их). Если вы должны это сделать (почему?) затем позаботьтесь о том, чтобы точно знать, как ваши объекты класса будут в памяти, и будьте осторожны, чтобы избежать наследования.


разница в том, что этот трюк действителен только для типов POD. Вот, собственно, и все. Стандарт указывает, что это приведение допустимо для типа POD, но не дает никаких гарантий относительно того, что происходит с типами без POD.


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

например, сочетание открытых, частных и защищенных переменных-членов может быть выложено таким образом, чтобы каждый тип доступа был непрерывным. Или производные классы могут иметь переменные-члены, чередующиеся с неиспользуемым пространством в супер классе.

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

POD отличается тем, что он должен быть совместим с C.


обычно не имеет значения, имеет ли класс конструктор: важно, имеет ли класс какие-либо виртуальные методы. Для деталей, google для "vtable" и "vptr".