C++: Каков размер объекта пустого класса?

Мне было интересно, что может быть размером с объект пустого класса. Это, конечно, не может быть 0 байтов, поскольку должна быть возможность ссылаться и указывать на него, как на любой другой объект. Но насколько велик такой объект?

Я использовал эту маленькую программу:

#include <iostream>
using namespace std;

class Empty {};

int main()
{
    Empty e;
    cerr << sizeof(e) << endl;
    return 0;
}

Выходные данные, полученные на компиляторах Visual C++ и Cygwin-g++, составляли 1 байт! Это было немного удивительно для меня, так как я ожидал, что оно будет иметь размер машинного слова (32 бита или 4 байта).

Может кто-нибудь объяснить, почему размер 1 байт? Почему не 4 байта? Это зависит от компилятора или машины тоже? Кроме того, может ли кто-то привести более убедительную причину того, почему пустой объект класса не будет иметь размер 0 байт?

17 ответов

Решение

Цитируя часто задаваемые вопросы Bjarne Stroustrup по стилю и технике C++, причина, по которой размер отличен от нуля, заключается в том, чтобы "гарантировать, что адреса двух разных объектов будут разными". И размер может быть 1, потому что выравнивание здесь не имеет значения, так как на самом деле смотреть не на что.

Стандарт гласит, что все большинство производных объектов имеют sizeof() >= 1:

Если это не битовое поле (class.bit), наиболее производный объект должен иметь ненулевой размер и занимать один или несколько байтов памяти. Подобъекты базового класса могут иметь нулевой размер. ISO / IEC FDIS 14882: 1998 (E) intro.object

Это действительно деталь реализации. Когда-то давно я думал, что это может быть ноль или тысяча байтов, что это не имеет отношения к спецификации языка. Но, посмотрев на стандарт (раздел 5.3.3), sizeof определяется как всегда возвращающий один или более, несмотря ни на что.

Размер наиболее производного класса должен быть больше нуля.

Это необходимо, помимо прочего, для того, чтобы вы могли обрабатывать массивы объектов и указатели на них. Если вашим элементам было разрешено быть нулевого размера, то &(array[0]) будет идентичен &(array[42]), который будет вызывать всевозможные разрушения для ваших циклов обработки.

Причина, по которой это может быть не машинное слово, состоит в том, что в нем нет элементов, которые фактически требуют его выравнивания по границе слова (например, целое число). Например, если вы разместите char x; int y; внутри класса мой GCC синхронизирует его на восьми байтах (так как второй int должен быть выровнен в этой реализации).

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

Есть исключение: массивы 0-длины

#include <iostream>

class CompletlyEmpty {
  char NO_DATA[0];
};

int main(int argc, const char** argv) {
  std::cout << sizeof(CompletlyEmpty) << '\n';
}

Я думаю, что было бы полезно дать ссылку на ответ, объясняющий это тоже хорошо. Речь идет о boost::compressed_pair Logan Capaldo.

Это может помочь вам:-) http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a

Размер пустого класса или структуры равен 1

Причина, по которой это происходит, сводится к правильной реализации стандарта. Одна из вещей, которую стандарт C++ говорит, заключается в том, что "ни один объект не должен иметь такой же адрес в памяти, как любая другая переменная".... Какой самый простой способ обеспечить это? Убедитесь, что все типы имеют ненулевой размер. Чтобы добиться этого, компилятор добавляет фиктивный байт к структурам и классам, которые не имеют элементов данных и виртуальных функций, так что они имеют размер 1, а не 0, и тогда они гарантированно будут иметь уникальный адрес памяти.

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

Выделение 1 байта для пустого класса зависит от компилятора. Компиляторы должны убедиться, что объекты находятся в разных местах памяти, и им необходимо выделить ненулевой объем памяти для объекта. Послушайте заметки на эту тему здесь: http://listenvoice.com/listenVoiceNote.aspx?id=27

Хотя компиляторы выделяют ненулевой размер пустому классу, они также проводят оптимизацию, когда новые классы получены из пустых классов. Слушайте об пустой пустой оптимизации на вопросах интервью на ListenVoice C++.

Я думаю, что этот вопрос имеет только теоретический интерес, но не имеет значения на практике.

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

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

Итог: если вы пишете пустой класс X, просто сделайте все функции-члены статическими. Тогда вам не нужно будет создавать X-объекты, и на производные классы это никак не повлияет.

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

и то, что вы сказали: "Это было немного удивительно для меня, так как я ожидал, что оно будет иметь размер машинного слова (32 бита или 4 байта)". будет истинно для ссылочной переменной (машинные слова) типа empty(), а не размера самого класса (который является абстрактным типом данных),

#include<iostream>
using namespace std;


    class Empty { };
    int main()
    {
        Empty* e1 = new Empty;
        Empty* e2 = new Empty;

        if (e1 == e2)
            cout << "Alas same address of two objects" << endl;
        else
            cout << "Okay it's Fine to have different addresses" << endl;

        return 0;
    }

Вывод: Хорошо, хорошо иметь разные адреса

Возвращение размера 1 гарантирует, что два объекта не будут иметь одинаковый адрес.

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

Пустой класс - этот класс не содержит никакого содержимого.

любой класс, который не является пустым, будет представлен его содержимым в памяти.

Теперь, как пустой класс будет представлен в памяти? поскольку у него нет содержимого, нет способа показать его существование в памяти, но класс присутствует, обязательно показать его присутствие в памяти. Чтобы показать наличие пустого класса в памяти, требуется 1 байт.

Для объекта пустого класса компилятор выделяет 1 байт для уникальной идентификации адреса. Итак, если у класса есть несколько объектов, они могут иметь разные уникальные ячейки памяти. Предположим, что если класс не имеет размера, что будет храниться в этой области памяти? По этой причине, когда мы создаем объект пустого класса в программе на C++, ему требуется некоторая память для хранения, а минимальный объем памяти, который можно зарезервировать, составляет 1 байт. Итак, если мы создадим несколько объектов пустого класса, каждый объект будет иметь уникальный адрес.

Ниже примера кода C++ всегда будет предоставлен уникальный адрес для обоих объектов, созданных для пустого класса EmptyClass.

      int main()
{
    EmptyClass obj1;
    EmptyClass obj2;
     
    if (&obj1 == &obj2){
         cout << "Both objects have same address" << endl;
    }else{
        cout << "Both objects have unique address" << endl;
    }       
    return 0;
}

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

Это из-за этого указателя, хотя указатель (целое число) из 4 байтов, но он относится к одной ячейке памяти (один блок), которая составляет 1 байт.

Другие вопросы по тегам