C ++: qual è la dimensione di un oggetto di una classe vuota?


111

Mi chiedevo quale potesse essere la dimensione di un oggetto di una classe vuota . Sicuramente non potrebbe essere 0 byte poiché dovrebbe essere possibile fare riferimento e puntare ad esso come qualsiasi altro oggetto. Ma quanto è grande un oggetto del genere?

Ho usato questo piccolo programma:

#include <iostream>
using namespace std;

class Empty {};

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

L'output che ho ottenuto su entrambi i compilatori Visual C ++ e Cygwin-g ++ era di 1 byte ! Questo è stato un po 'sorprendente per me poiché mi aspettavo che fosse della dimensione della parola macchina (32 bit o 4 byte).

Qualcuno può spiegare perché la dimensione di 1 byte? Perché non 4 byte? Dipende anche dal compilatore o dalla macchina? Inoltre, qualcuno può fornire una ragione più convincente per cui un oggetto di classe vuoto non sarà di dimensione 0 byte?


Non vedo motivo per cui non possa essere zero. Ma dandogli una dimensione altre cose sono più facili nel compilatore. Se hai una serie di queste cose, ogni elemento necessita di un indirizzo univoco. Una dimensione di 1 lo rende facile.
Martin York

2
Può essere di dimensione zero se è un oggetto secondario della classe base.
Johannes Schaub - litb

Risposte:


129

Citando le domande frequenti su stile e tecnica C ++ di Bjarne Stroustrup , il motivo per cui la dimensione è diversa da zero è "Per garantire che gli indirizzi di due oggetti diversi siano diversi". E la dimensione può essere 1 perché l'allineamento non ha importanza qui, poiché non c'è nulla da guardare effettivamente.


55
Bah, cosa diavolo ne saprebbe del C ++? :-)
paxdiablo

18
@Lazer, perché non ci sono strutture vuote in C.
aib

7
@nurabha I punti questo puntatore per l'oggetto. Non è memorizzato nell'oggetto. Se, tuttavia, sono presenti funzioni virtuali, l'oggetto contiene un puntatore a vtable.
tbleher

4
@krish_oza: pensi male. Quando si alloca una variabile sullo stack, non può occupare zero byte (perché variabili diverse richiedono indirizzi diversi), quindi la dimensione minima 1. Dopodiché, spetta al compilatore. Allo stesso modo con new; quando lo spazio viene allocato, un'altra allocazione deve avere un indirizzo diverso. E così via. Non c'è necessariamente alcun puntatore coinvolto nella classe vuota; potrebbero esserci puntatori alle variabili (o riferimenti o allocazioni locali / stack), ma non sono di dimensione zero e non sono necessariamente dimensioni del puntatore.
Jonathan Leffler

3
@Destructor, non più intelligente ma so cos'è una faccina :-) Potresti voler rileggere il commento sotto quella luce e capire che era umorismo.
paxdiablo

30

Lo standard afferma che tutti gli oggetti più derivati ​​hanno sizeof ()> = 1:

A meno che non sia un campo di bit (class.bit), un oggetto più derivato deve avere una dimensione diversa da zero e occupare uno o più byte di memoria. Gli oggetti secondari della classe base possono avere dimensione zero. ISO / IEC FDIS 14882: 1998 (E) intro.object


1
Lo trovo difficile da credere. Lo standard fa di tutto per assicurarsi che le implementazioni abbiano mano libera per fare un buon lavoro di ottimizzazione legare le mani dell'implementatore in questo modo non sembra il tipo di cosa che fa normalmente lo standard (potrei sbagliarmi)
Martin York,

4
@eSKay: è necessario affinché oggetti diversi ottengano indirizzi diversi. Non potresti avere una mappa di puntatori a oggetti, ad esempio, se istanze diverse avessero lo stesso indirizzo.
Brian Neal

14

Questo è davvero un dettaglio di implementazione. Una volta, molto tempo fa, pensavo che potesse essere zero byte o mille byte, che non ha alcuna relazione con le specifiche del linguaggio. Ma, dopo aver esaminato lo standard (sezione 5.3.3), sizeofviene definito come restituirne sempre uno o più, qualunque cosa accada.

La dimensione di una classe più derivata deve essere maggiore di zero.

Ciò è necessario, tra le altre cose, per consentire di gestire array di oggetti e puntatori ad essi. Se ai tuoi elementi fosse consentito di essere di dimensione zero, allora &(array[0])sarebbe identico a &(array[42]), il che causerà ogni sorta di caos ai tuoi loop di elaborazione.

Il motivo per cui potrebbe non essere una parola macchina è che non ci sono elementi al suo interno che effettivamente richiedono che sia allineato su un confine di parola (come un numero intero). Ad esempio, se si inserisce char x; int y;all'interno della classe, il mio GCC lo sincronizza a otto byte (poiché il secondo int deve essere allineato in quell'implementazione).


Il motivo del "diverso da zero" è che oggetti diversi dovrebbero avere indirizzi diversi. Immagina un array di oggetti di dimensione zero. Come indicizzeresti? In alcuni casi, il compilatore è permesso di ottimizzare questa via anche se (la classe base vuota ottimizzazioni)
JALF

@jalf: "Come indicizzeresti?" Allo stesso modo in C (per un array di oggetti struct, ad esempio) ??
Lazer

1
@ eSKay - Non potresti se avessero 0 dimensioni. Sarebbero tutti all'elemento 0.
Brian Neal,

1
@BrianNeal che non è un problema, dal momento che non hanno uno stato per differenziarsi. I problemi arrivano solo se si considerano i suggerimenti.
gha.st

2
O prendendo la dimensione di detto array per calcolarne la lunghezza.
gha.st

6

C'è un'eccezione: array di lunghezza 0

#include <iostream>

class CompletlyEmpty {
  char NO_DATA[0];
};

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

Perché nessuno ha commentato questa risposta? Mi sembra molto curioso.
Peregring-lk

Se crei due oggetti "CompletelyEmpty" ('a' e 'b' per esempio), sizeof dice che sono lunghi 0 byte, ma i suoi indirizzi sono diversi ('& a == & b' restituisce false). E questo dovrebbe essere impossibile ... (usando g ++ 4.7.2).
Peregring-lk

1
Ma se crei un array di questi oggetti, diciamo c, &c[M] == &c[N]per ogni Me N(clang ++ 4.1).
Konstantin Nikitin

5
C e C ++ non consentono array di lunghezza zero. Il tuo compilatore potrebbe, ma non è corretto.
Konrad Borowski

sì, la dimensione della classe stessa è zero, ma un'istanza di questa classe è ancora 1 byte.
ZeR0

5

Anche se non è necessario assegnare memoria per una classe vuota, ma per creare oggetti di classi vuote, il compilatore assegna la memoria minima che può essere assegnata, che è 1 byte. In questo modo il compilatore può distinguere in modo univoco due oggetti della stessa classe vuota e sarà in grado di assegnare l'indirizzo dell'oggetto a un puntatore del tipo di classe vuota.



3

Questo può aiutarti :-) http://bytes.com/topic/c/insights/660463-sizeof-empty-class-structure-1-a

La dimensione di una classe o struttura vuota è 1

Il motivo per cui ciò accade si riduce all'implementazione corretta dello standard, una delle cose che lo standard C ++ dice è che "nessun oggetto deve avere lo stesso indirizzo in memoria di qualsiasi altra variabile" .... Qual è il modo più semplice per assicurarlo? Assicurati che tutti i tipi abbiano una dimensione diversa da zero. Per ottenere ciò, il compilatore aggiunge un byte fittizio a strutture e classi che non hanno membri di dati e funzioni virtuali in modo che abbiano una dimensione di 1 anziché una dimensione di 0 e quindi è garantito che abbiano un indirizzo di memoria univoco.


2

L'assegnazione di 1 byte per una classe vuota dipende dal compilatore. I compilatori devono assicurarsi che gli oggetti risiedano in posizioni di memoria diverse e devono allocare una dimensione di memoria diversa da zero a un oggetto. Ascolta le note su questo argomento qui: http://listenvoice.com/listenVoiceNote.aspx?id=27

Anche se i compilatori allocano dimensioni diverse da zero a una classe vuota, eseguono anche ottimizzazioni quando nuove classi derivano da classi vuote. Ascolta l'ottimizzazione della base vuota sulle domande dell'intervista di programmazione c ++ di ListenVoice.


2

il motivo per la classe senza membri di dati ma con dimensione 1 byte è che questo * testo forte * deve essere archiviato in memoria in modo che un riferimento o un puntatore possa puntare all'oggetto di quella classe


0

classe vuota -quella classe non contiene alcun contenuto.

qualsiasi classe che non sia vuota sarà rappresentata dal suo contenuto in memoria.

ora come sarà rappresentata la classe vuota nella memoria? siccome non ha contenuto nessun modo per mostrare la sua esistenza nella memoria, ma la classe è presente, è obbligatorio mostrare la sua presenza nella memoria. Per mostrare la presenza di una classe vuota in memoria è richiesto 1 byte.


0

Penso che sia così perché 1 byte è l'unità di memoria più piccola che può essere utilizzata come segnaposto e non può dare dimensione zero in quanto non sarà possibile creare un array di oggetti ..

e la cosa che hai detto "Questo è stato un po 'sorprendente per me poiché mi aspettavo che fosse della dimensione della parola macchina (32 bit o 4 byte)." sarà vero per la variabile di riferimento (parole macine) di tipo empty (), non per la dimensione della classe stessa (che è un tipo di dati astratto),


0

Penso che questa domanda sia solo di interesse teorico ma non ha importanza nella pratica.

Come già sottolineato da altri, derivare da una classe vuota non fa alcun danno, in quanto ciò non consumerà memoria extra per la porzione della classe base.

Inoltre, se una classe è vuota (il che significa che, in teoria, non necessita di memoria per istanza, ovvero non ha membri di dati non statici o funzioni membro virtuali), allora tutte le sue funzioni membro possono (e dovrebbe) essere definito come statico. Quindi non è necessario creare mai un'istanza di questa classe.

Conclusione: se ti ritrovi a scrivere una classe X vuota, rendi statiche tutte le funzioni membro. Quindi non sarà necessario creare oggetti X e le classi derivate non saranno influenzate in alcun modo.


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;
    }

Risultato: va bene avere indirizzi diversi

La restituzione della dimensione 1 garantisce che i due oggetti non avranno lo stesso indirizzo.


0

È diverso da zero per garantire che i due diversi oggetti abbiano indirizzi diversi. Oggetti diversi dovrebbero avere indirizzi diversi, quindi la dimensione di una classe vuota è sempre 1 byte.


-2

Penso che se la dimensione di una classe vuota è zero significa che non esiste. Affinché esista (classe), è necessario che abbia almeno 1 byte, poiché questo byte è l'indirizzo di memoria / riferimento.


-3

È a causa di questo puntatore, sebbene il puntatore sia (intero) di 4 byte ma si riferisca a una posizione di memoria (una unità) che è di 1 byte.


5
Scusa, ma non ha senso.
jogojapan

@Narayan das khatri: in primo luogo il tipo di puntatore dipende dal tipo di dati che non è sempre int e in secondo luogo la dimensione del puntatore dipende dalla macchina e dal compilatore su macchine a 32 bit è 4 byte e per macchine a 64 bit è 8 byte.
Krishna Oza
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.