C ++: Wie groß ist ein Objekt einer leeren Klasse?

111

Ich habe mich gefragt, wie groß ein Objekt einer leeren Klasse sein könnte . Es könnte sicherlich nicht 0 Bytes sein, da es möglich sein sollte, wie jedes andere Objekt darauf zu verweisen und darauf zu zeigen. Aber wie groß ist ein solches Objekt?

Ich habe dieses kleine Programm benutzt:

#include <iostream>
using namespace std;

class Empty {};

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

Die Ausgabe, die ich sowohl auf Visual C ++ - als auch auf Cygwin-g ++ - Compilern erhielt, war 1 Byte ! Dies war für mich ein wenig überraschend, da ich erwartet hatte, dass es die Größe des Maschinenworts hat (32 Bit oder 4 Bytes).

Kann jemand erklären, warum die Größe von 1 Byte? Warum nicht 4 Bytes? Ist dies auch vom Compiler oder der Maschine abhängig? Kann jemand einen schlüssigeren Grund dafür angeben, warum ein leeres Klassenobjekt nicht die Größe 0 Bytes hat?

Ashwin Nanjappa
quelle
Ich sehe keinen Grund, warum es nicht Null sein konnte. Aber wenn man ihm eine Größe gibt, sind andere Dinge im Compiler einfacher. Wenn Sie ein Array dieser Dinge haben, benötigt jedes Element eine eindeutige Adresse. Eine Größe von 1 macht dies einfach.
Martin York
2
Es kann eine Größe von Null haben, wenn es sich um ein Unterobjekt der Basisklasse handelt.
Johannes Schaub - litb

Antworten:

129

In den häufig gestellten Fragen zu C ++ - Stil und Technik von Bjarne Stroustrup wird angegeben , dass die Größe ungleich Null ist: "Um sicherzustellen, dass die Adressen von zwei verschiedenen Objekten unterschiedlich sind." Und die Größe kann 1 sein, da die Ausrichtung hier keine Rolle spielt, da es nichts zu sehen gibt.

Sol
quelle
55
Bah, was zum Teufel würde er über C ++ wissen? :-)
paxdiablo
18
@Lazer, weil es in C. keine leeren Strukturen gibt
aib
7
@nurabha Der Zeiger this zeigt auf das Objekt. Es ist nicht im Objekt gespeichert. Wenn jedoch virtuelle Funktionen vorhanden sind, enthält das Objekt einen Zeiger auf die vtable.
Tbleher
4
@krish_oza: du denkst falsch. Wenn Sie eine Variable auf dem Stapel zuweisen, kann sie keine Null-Bytes belegen (da unterschiedliche Variablen unterschiedliche Adressen benötigen), daher die Mindestgröße 1. Danach liegt es am Compiler. Ähnlich mit new; Wenn der Speicherplatz zugewiesen wird, muss eine andere Zuweisung eine andere Adresse haben. Und so weiter. In der leeren Klasse ist nicht unbedingt ein Zeiger enthalten. Möglicherweise gibt es Zeiger auf die Variablen (oder Referenzen oder lokale / Stapelzuordnungen), aber sie haben keine Größe von Null und sie müssen nicht unbedingt Zeigergröße haben.
Jonathan Leffler
3
@Destructor, nicht schlauer, aber ich weiß, was ein Smiley ist :-) Vielleicht möchten Sie den Kommentar in diesem Licht noch einmal lesen und feststellen, dass es Humor war.
Paxdiablo
30

Der Standard besagt, dass alle am meisten abgeleiteten Objekte sizeof ()> = 1 haben:

Sofern es sich nicht um ein Bitfeld (class.bit) handelt, muss ein am meisten abgeleitetes Objekt eine Größe ungleich Null haben und ein oder mehrere Bytes Speicher belegen. Unterobjekte der Basisklasse können eine Größe von Null haben. ISO / IEC FDIS 14882: 1998 (E) intro.object

TrayMan
quelle
1
Ich finde das schwer zu glauben. Der Standard geht von seiner Art und Weise, um sicherzustellen , Implementierungen freie Hand hat eine gute Arbeit der Optimierung zu tun , um die Hände der Implementierer wie das Binden klingt nicht wie die Art der Sache , der Standard normalerweise nicht (ich könnte falsch sein)
Martin York
4
@eSKay - Dies ist erforderlich, damit unterschiedliche Objekte unterschiedliche Adressen erhalten. Sie könnten beispielsweise keine Karte mit Zeigern auf Objekte haben, wenn verschiedene Instanzen dieselbe Adresse hätten.
Brian Neal
14

Das ist wirklich ein Implementierungsdetail. Vor langer Zeit dachte ich, es könnten null oder tausend Bytes sein, was keinen Einfluss auf die Sprachspezifikation hat. Nach Betrachtung des Standards (Abschnitt 5.3.3) wird sizeofjedoch definiert, dass immer einer oder mehrere zurückgegeben werden, egal was passiert .

Die Größe einer am meisten abgeleiteten Klasse muss größer als Null sein.

Dies ist unter anderem erforderlich, damit Sie Arrays von Objekten und Zeigern auf diese verarbeiten können. Wenn Ihre Elemente die Größe Null haben könnten, &(array[0])wäre dies identisch mit &(array[42]), was Ihre Verarbeitungsschleifen in jeder Hinsicht verwüsten würde.

Der Grund, warum es möglicherweise kein Maschinenwort ist, besteht darin, dass es keine Elemente enthält, die tatsächlich erfordern, dass es an einer Wortgrenze (z. B. einer Ganzzahl) ausgerichtet wird. Wenn Sie beispielsweise char x; int y;innerhalb der Klasse platzieren, taktet mein GCC sie mit acht Bytes (da das zweite int in dieser Implementierung ausgerichtet sein muss).

paxdiablo
quelle
Der Grund für das "nicht Null" ist, dass unterschiedliche Objekte unterschiedliche Adressen haben sollten. Stellen Sie sich ein Array von Objekten mit der Größe Null vor. Wie würden Sie es indizieren? In einigen Fällen kann der Compiler dies jedoch optimieren (die leere Basisklassenoptimierung)
Jalf
@jalf: "Wie würden Sie es indizieren?" Genauso wie ich es in C machen würde (zum Beispiel für ein Array von Strukturobjekten)?
Lazer
1
@eSKay - Sie könnten nicht, wenn sie 0 Größe hätten. Sie wären alle bei Element 0.
Brian Neal
1
@BrianNeal was kein Problem ist, da sie keinen Zustand haben, um sich zu differenzieren. Die Probleme treten nur auf, wenn Sie Zeiger berücksichtigen.
Gha.st
2
Oder nehmen Sie die Größe des Arrays, um seine Länge zu berechnen.
Gha.st
6

Es gibt eine Ausnahme: Arrays mit einer Länge von 0

#include <iostream>

class CompletlyEmpty {
  char NO_DATA[0];
};

int main(int argc, const char** argv) {
  std::cout << sizeof(CompletlyEmpty) << '\n';
}
Konstantin Nikitin
quelle
Warum hat niemand diese Antwort kommentiert? Es scheint sehr neugierig für mich.
Peregring-lk
Wenn Sie zwei "CompletelyEmpty" -Objekte erstellen (z. B. 'a' und 'b'), gibt sizeof an, dass sie 0 Byte lang sind, die Adressen jedoch unterschiedlich sind ('& a == & b' wertet false aus). Und das sollte unmöglich sein ... (mit g ++ 4.7.2).
Peregring-lk
1
Aber wenn Sie erstellen ein Array dieser Objekte, sagen wir, c, &c[M] == &c[N]für jeden Mund N(Klirren ++ 4.1).
Konstantin Nikitin
5
C und C ++ erlauben keine Arrays mit der Länge Null. Ihr Compiler könnte, aber es ist falsch.
Konrad Borowski
Ja, die Klassengröße selbst ist Null, aber eine Instanz dieser Klasse ist immer noch 1 Byte.
ZeR0
5

Obwohl es nicht erforderlich ist, einer leeren Klasse Speicher zuzuweisen, sondern um Objekte aus leeren Klassen zu erstellen, weist der Compiler den minimalen Speicher zu, der zugewiesen werden kann, nämlich 1 Byte. Auf diese Weise kann der Compiler zwei Objekte derselben leeren Klasse eindeutig unterscheiden und die Adresse des Objekts einem Zeiger des leeren Klassentyps zuweisen.

lalatendu
quelle
4

Ich denke, es könnte hilfreich sein, auf eine Antwort zu verlinken, die dies auch gut erklärt. Es ist etwa boost::compressed_pairvon Logan Capaldo .

Johannes Schaub - litb
quelle
3

Dies kann Ihnen helfen :-) http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a

Die Größe einer leeren Klasse oder Struktur beträgt 1

Der Grund dafür ist die ordnungsgemäße Implementierung des Standards. Der C ++ - Standard sagt unter anderem, dass "kein Objekt dieselbe Adresse im Speicher haben darf wie jede andere Variable" .... Was ist der einfachste Weg, dies sicherzustellen? Stellen Sie sicher, dass alle Typen eine Größe ungleich Null haben. Um dies zu erreichen, fügt der Compiler Strukturen und Klassen, die keine Datenelemente und keine virtuellen Funktionen haben, ein Dummy-Byte hinzu, sodass sie eine Größe von 1 anstelle einer Größe von 0 haben und dann garantiert eine eindeutige Speicheradresse haben.

Arsalan Mehmood
quelle
2

Die Zuweisung von 1 Byte für eine leere Klasse ist vom Compiler abhängig. Compiler müssen sicherstellen, dass sich Objekte an verschiedenen Speicherorten befinden, und sie müssen einem Objekt eine Speichergröße ungleich Null zuweisen. Hören Sie sich hier Notizen zu diesem Thema an: http://listenvoice.com/listenVoiceNote.aspx?id=27

Obwohl Compiler einer leeren Klasse eine Größe ungleich Null zuweisen, führen sie auch Optimierungen durch, wenn neue Klassen aus leeren Klassen abgeleitet werden. Informieren Sie sich über die Optimierung der leeren Basis in den Interviewfragen von ListenVoice zur C ++ - Programmierung.

user332764
quelle
2

Der Grund für eine Klasse ohne Datenelemente mit einer Größe von 1 Byte ist, dass dieser * starke Text * im Speicher gespeichert werden muss, damit eine Referenz oder ein Zeiger auf das Objekt dieser Klasse verweisen kann

Ramiz
quelle
0

leere Klasse - Diese Klasse enthält keinen Inhalt.

Jede Klasse, die nicht leer ist, wird durch ihren Inhalt im Speicher dargestellt.

Wie wird nun die leere Klasse im Speicher dargestellt? Da es keinen Inhalt gibt, der seine Existenz im Speicher nicht zeigen kann, aber eine Klasse vorhanden ist, ist es obligatorisch, seine Präsenz im Speicher zu zeigen. Um die Präsenz einer leeren Klasse im Speicher anzuzeigen, ist 1 Byte erforderlich.

Ganesh
quelle
0

Ich denke, das ist so, weil 1 Byte die kleinste Speichereinheit ist, die als Platzhalter verwendet werden kann, und keine Größe von Null angegeben werden kann, da es nicht möglich ist, ein Array von Objekten zu erstellen.

und die Sache, die Sie sagten "Das war ein wenig überraschend für mich, da ich erwartet hatte, dass es die Größe des Maschinenworts hat (32 Bit oder 4 Bytes)." gilt für die Referenzvariable (Macine-Wörter) vom Typ leer (), nicht für die Größe der Klasse selbst (die ein abstrakter Datentyp ist).

Lazarus
quelle
0

Ich denke, diese Frage ist nur von theoretischem Interesse, spielt aber in der Praxis keine Rolle.

Wie bereits von anderen erwähnt, schadet das Ableiten von einer leeren Klasse nicht, da dadurch kein zusätzlicher Speicher für den Basisklassenabschnitt verbraucht wird.

Wenn eine Klasse leer ist (was bedeutet, dass sie theoretisch keinen Instanzspeicher benötigt, dh keine nicht statischen Datenelemente oder virtuellen Elementfunktionen), können alle ihre Elementfunktionen genauso gut (und sollte) als statisch definiert werden. Es ist also nicht erforderlich, jemals eine Instanz dieser Klasse zu erstellen.

Fazit: Wenn Sie eine leere Klasse X schreiben, machen Sie einfach alle Elementfunktionen statisch. Sie müssen dann keine X-Objekte erstellen, und abgeleitete Klassen sind in keiner Weise betroffen.

Kidfisto
quelle
0
#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;
    }

Ausgabe: Okay, es ist in Ordnung, unterschiedliche Adressen zu haben

Durch die Rückgabe von Größe 1 wird sichergestellt, dass die beiden Objekte nicht dieselbe Adresse haben.

Sandeep_black
quelle
0

Es ist ungleich Null, um sicherzustellen, dass die beiden unterschiedlichen Objekte unterschiedliche Adressen haben. Unterschiedliche Objekte sollten unterschiedliche Adressen haben, sodass die Größe einer leeren Klasse immer 1 Byte beträgt.

Yadvendra Yadav
quelle
-2

Ich denke, wenn die Größe einer leeren Klasse Null ist, bedeutet dies, dass sie nicht existiert. Damit es (Klasse) existiert, muss es mindestens 1 Byte haben, da dieses Byte die Speicher- / Referenzadresse ist.

Honig
quelle
-3

Dies liegt an diesem Zeiger, obwohl der Zeiger (Ganzzahl) 4 Byte beträgt, sich jedoch auf einen Speicherplatz (eine Einheit) bezieht, der 1 Byte beträgt.

Narayan das khatri
quelle
5
Sorry, aber das ist Unsinn.
Jogojapan
@Narayan das khatri: Erstens hängt der Zeigertyp vom Datentyp ab, nicht immer int, und zweitens hängt die Größe des Zeigers von der Maschine und dem Compiler auf 32-Bit-Maschinen ab. 4 Byte und bei 64-Bit-Maschinen 8 Byte.
Krishna Oza