2010-05-13 12 views
9

Due citazioni dalla standard C++, §1.8:ottimizzazione classe base vuota

Un oggetto è una regione di stoccaggio.

I sottooggetti di classe base possono avere dimensione zero.

Non penso che un'area di archiviazione possa essere di dimensione zero. Ciò significherebbe che alcuni sottooggetti di classe base non sono in realtà oggetti. In che modo queste dichiarazioni coesistono?

+1

Perché pensi che una regione di archiviazione non può essere di dimensioni zero? Apparentemente può :) –

+1

Call malloc (0). – bmargulies

+1

@bmargulies 'malloc' è espressamente scritto in C in modo che non sia necessario creare un oggetto di dimensione zero:" Se la dimensione dello spazio richiesto è zero, il comportamento è definito dall'implementazione: viene restituito un puntatore nullo , o il comportamento è come se la dimensione fosse un valore diverso da zero " –

risposta

10

Un argomento filosofico sulla definizione di "regione" non è necessario.

1.8/5 dice "A meno che non sia un campo di bit, l'oggetto più derivato deve avere una dimensione diversa da zero ... Gli oggetti secondari di classe base possono avere dimensione zero".

Quindi lo standard è abbastanza chiaro quali oggetti (e quindi quali "aree di memoria") possono avere dimensione zero. Se non sei d'accordo con lo standard che cosa significa "regione" in inglese è una cosa, puoi criticare le abilità letterarie degli autori (non correlate alla programmazione). Del resto, puoi criticare le loro abilità poetiche (14.7.3/7). Ma è abbastanza chiaro ciò che lo standard dice qui sulle dimensioni degli oggetti dei tipi di classe.

Il modo pragmatico di leggere gli standard è che, date due interpretazioni plausibili di una parola, scegliere quella che non contraddice direttamente un'altra frase nella stessa sezione dello standard. Non scegliere quello che corrisponde più strettamente al tuo uso personale preferito della parola, o anche l'uso più comune.

+0

"A meno che non sia un campo di bit, l'oggetto più derivato deve avere una dimensione diversa da zero" sembra in conflitto con 'new int [0]' che si dice "assegna un array senza elementi". Questo implica che gli array in realtà * do * contengano padding interno in quel caso? –

+0

Non penso che un array sia un oggetto più derivato. 1.8/4: "Se un oggetto completo ... è di tipo classe, il tipo è considerato la classe più derivata ... un oggetto di un tipo di classe più derivato è chiamato l'oggetto più derivato" –

+0

@Steve dice " un oggetto di un tipo di classe più derivato o di un tipo non di classe è chiamato l'oggetto più derivato ". - Modifica: la formulazione C++ 03 sembra differire dalla dicitura FCD. –

9

C++ non consente un oggetto di dimensione zero, poiché ogni oggetto deve avere un indirizzo di memoria univoco. Quindi, se avete:

struct empty {}; 

// ... 

empty myempty; 
empty* ptr = &myempty; 

poi ptr deve puntare ad un indirizzo di memoria univoco. Lo standard afferma che la dimensione minima per un oggetto è 1 byte per questo scopo. Allo stesso modo, le allocazioni di dimensione 0 sono consentite e restituiscono un puntatore valido, anche se la scrittura su quel puntatore non è consentita (questo funziona per malloc(0) e new empty restituisce un puntatore a un byte, dal sizeof(empty) == 1).

Se io traggo da empty in questo modo:

struct derived : public empty 
{ 
    int data; 
} 

non v'è più alcun punto nella classe base empty che occupa un byte, perché tutti derived avranno un indirizzo univoco a causa del membro data. La citazione "Base subobjects di classe può avere dimensione zero" è presente per consentire, in questo caso, per il compilatore di non utilizzare alcuno spazio per empty, ad esempio sizeof(derived) == 4. Come afferma il titolo, è solo un'ottimizzazione, ed è perfettamente legale per la parte empty di derived occupare spazio zero.

+0

In realtà 'sizeof (vuoto)' può essere più grande, e la maggior parte dei compilatori renderà almeno la larghezza della parola macchina. –

+0

"ogni oggetto deve avere un indirizzo di memoria univoco" - nonostante la dicitura errata nello standard, ogni oggetto non è necessario per avere un indirizzo di memoria univoco. Un oggetto può avere lo stesso indirizzo di un suboject all'inizio e/o un sottooggetto di classe base. Dovrebbe dire che ogni oggetto _complete_ deve avere un indirizzo univoco. – davmac

2

Il C++ standard, 1.8.5 afferma: -

A meno che non si tratta di un campo di bit (9.6), un oggetto derivato più deve avere un non zero dimensioni e deve occupare uno o più byte di archiviazione. Classe base I sottooggetti possono avere dimensione zero. Un oggetto di tipo banale o di layout standard (3.9) devono occupare byte contigui di memoria.

Quindi, lo standard offre una classe base che non ha membri di dati (e non virtuali) per condividere lo stesso indirizzo di un altro subobject con un tipo distinto. Si può giocare con la dimensione vuota classe di base come ...

struct a{}; 
struct a1{}; 
struct b : public a, public a1{char c;}; 


int main() 
{ 
    std::cout << sizeof(b) << "\n"; 
    std::cout << sizeof(b::a); 
} 


Which outputs (ignoring padding)... 

1 
1 


now try: 


struct a{}; 
struct b : public a {a ax;}; 


int main() 
{ 
    std::cout << sizeof(b) << "\n"; 
    std::cout << sizeof(b::a); 
} 


and the output is ... 

2 
1 

perché le due istanze di un (come base e come membro) devono avere indirizzi distinti.

BTW: "b :: a" è un altro modo per dire "a". La presenza dell'operatore di accesso all'ambito non richiede il "subobject di classe base di b di tipo a". Il versetto 5.3.3/2 dice: - Quando si applica sizeof a un sottooggetto di classe base, il risultato è la dimensione del tipo di quell'oggetto.