Пустая структура в C ++ не имеет нулевого размера [дубликат]

В терминах шкалы величин:

Если epsilon - малая доля величины величины (то есть относительной величины) в некотором определенном физическом смысле и A и B типа сопоставим в том же смысле, что я думаю, что следующее вполне корректно:

#include <limits>
#include <iomanip>
#include <iostream>

#include <cmath>
#include <cstdlib>
#include <cassert>

template< typename A, typename B >
inline
bool close_enough(A const & a, B const & b,
                  typename std::common_type< A, B >::type const & epsilon)
{
    using std::isless;
    assert(isless(0, epsilon)); // epsilon is a part of the whole quantity
    assert(isless(epsilon, 1));
    using std::abs;
    auto const delta = abs(a - b);
    auto const x = abs(a);
    auto const y = abs(b);
    // comparable generally and |a - b| < eps * (|a| + |b|) / 2
    return isless(epsilon * y, x) && isless(epsilon * x, y) && isless((delta + delta) / (x + y), epsilon);
}

int main()
{
    std::cout << std::boolalpha << close_enough(0.9, 1.0, 0.1) << std::endl;
    std::cout << std::boolalpha << close_enough(1.0, 1.1, 0.1) << std::endl;
    std::cout << std::boolalpha << close_enough(1.1,    1.2,    0.01) << std::endl;
    std::cout << std::boolalpha << close_enough(1.0001, 1.0002, 0.01) << std::endl;
    std::cout << std::boolalpha << close_enough(1.0, 0.01, 0.1) << std::endl;
    return EXIT_SUCCESS;
}
90
задан Ashwin Nanjappa 7 March 2009 в 11:36
поделиться

16 ответов

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

110
ответ дан Lena Schimmel 21 August 2018 в 11:49
поделиться
  • 1
    Ба, что он знает о C ++? :-) – paxdiablo 17 March 2009 в 05:37
  • 2
    @Lazer, потому что в C. нет пустых структур. – aib 4 November 2010 в 11:16
  • 3
    @nurabha Этот указатель указывает на объект на . Он не хранится в объекте. Если, однако, существуют виртуальные функции, объект содержит указатель на vtable. – tbleher 19 September 2013 в 18:03
  • 4
    @krish_oza: вы ошибаетесь. Когда вы выделяете переменную в стеке, она не может занимать нулевые байты (поскольку разные переменные нужны разные адреса), поэтому минимальный размер 1. После этого это зависит от компилятора. Аналогично new; когда пространство выделено, другое распределение должно иметь другой адрес. И так далее. В пустом классе необязательно есть указатель; могут быть указатели на переменные (или ссылки или локальные / стековые распределения), но они не являются нулевым размером, и они не обязательно являются размером указателя. – Jonathan Leffler 28 February 2014 в 22:35
  • 5
    @Destructor, а не умнее, но я знаю, что такое смайлик :-) Возможно, вы захотите перечитать комментарий в этом свете и понять, что это был юмор. – paxdiablo 3 April 2016 в 22:20

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

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

28
ответ дан Cheers and hth. - Alf 21 August 2018 в 11:49
поделиться
  • 1
    Я считаю, что трудно поверить. Стандарт выходит из своего пути, чтобы убедиться, что в реализациях есть свободная рука, чтобы сделать хорошую работу по оптимизации, связав руки исполнителя, как будто это не похоже на то, что обычно делает стандарт (я мог ошибаться) – Martin York 7 March 2009 в 11:35
  • 2
    Это на самом деле решает многие проблемы. – Brian Neal 7 March 2009 в 22:00
  • 3
    @Brian Neal: например? – Lazer 16 May 2010 в 06:22
  • 4
    @eSKay - требуется, чтобы разные объекты получали разные адреса. У вас не могло быть карты указателей на объекты, например, если разные экземпляры имели один и тот же адрес. – Brian Neal 16 May 2010 в 18:34

Я думаю, что было бы полезно сослаться на ответ, объясняющий это тоже. Это о boost::compressed_pair на Логан Капальдо .

4
ответ дан Community 21 August 2018 в 11:49
поделиться
0
ответ дан Ganesh 21 August 2018 в 11:49
поделиться

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

-2
ответ дан Jason Aller 21 August 2018 в 11:49
поделиться

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

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

0
ответ дан jazzz 21 August 2018 в 11:49
поделиться

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

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

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

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

0
ответ дан kidfisto 21 August 2018 в 11:49
поделиться

Существует исключение: массивы длиной 0 строк

#include <iostream>

class CompletlyEmpty {
  char NO_DATA[0];
};

int main(int argc, const char** argv) {
  std::cout << sizeof(CompletlyEmpty) << '\n';
}
5
ответ дан Konstantin Nikitin 21 August 2018 в 11:49
поделиться
  • 1
    Почему никто не прокомментировал этот ответ? Мне кажется очень любопытным. – Peregring-lk 31 December 2012 в 12:50
  • 2
    Если вы создадите два «CompletelyEmpty & quot; объекты (например, 'a' и 'b'), sizeof говорит, что они имеют длину 0 байт, но его адреса различаются ('& amp; a == & amp; b' вычисляет false). И это должно быть невозможно ... (с использованием g ++ 4.7.2). – Peregring-lk 31 December 2012 в 12:55
  • 3
    Но если вы создадите массив этих объектов, скажем, c, &c[M] == &c[N] для каждого M и N (clang ++ 4.1). – Konstantin Nikitin 1 January 2013 в 17:28
  • 4
    C и C ++ не допускают массивы нулевой длины. Возможно, ваш компилятор, но это неверно. – Konrad Borowski 14 April 2013 в 13:44
  • 5
    да, сам размер класса равен нулю, но экземпляр этого класса по-прежнему равен 1 байт. – ZeR0 5 September 2013 в 14:16
5
ответ дан lalatendu 21 August 2018 в 11:49
поделиться

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

-3
ответ дан Narayan das khatri 21 August 2018 в 11:49
поделиться
  • 1
  • 2
    @Narayan das khatri: сначала тип указателя зависит от типа данных его не int всегда, а второй размер указателя зависит от машины и компилятора на 32-битных машинах, это 4 байта, а для 64-битных машин - 8 байт. – darth_coder 29 January 2014 в 07:16

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

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

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

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

10
ответ дан paxdiablo 21 August 2018 в 11:49
поделиться
  • 1
    Причина "не нулевой" что разные объекты должны иметь разные адреса. Представьте себе массив объектов с нулевым размером. Как бы вы его проиндексировали? В некоторых случаях компилятору разрешено оптимизировать этот вариант (пустая оп тификация базового класса) – jalf 7 March 2009 в 12:07
  • 2
    @jalf: «Как бы вы его проиндексировали? & quot; Точно так же я бы сделал в C (например, для массива объектов struct)? – Lazer 16 May 2010 в 06:24
  • 3
    @eSKay - Вы не могли, если бы у них был 0 размер. Все они будут в элементе 0. – Brian Neal 16 May 2010 в 18:35
  • 4
    @BrianNeal, что не проблема, поскольку у них нет никакого государства, чтобы различать себя. Проблемы возникают только при рассмотрении указателей. – gha.st 15 May 2013 в 11:16
  • 5
    Или взять размер указанного массива для вычисления его длины. – gha.st 15 May 2013 в 11:18

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

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

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

3
ответ дан Peter O. 21 August 2018 в 11:49
поделиться

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

2
ответ дан Ramiz 21 August 2018 в 11:49
поделиться
#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 гарантирует, что два объекта не будут иметь один и тот же адрес.

0
ответ дан Sandy 21 August 2018 в 11:49
поделиться

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

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

2
ответ дан user332764 21 August 2018 в 11:49
поделиться

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

0
ответ дан Yadvendra Yadav 21 August 2018 в 11:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: