2016-02-04 20 views
9

Se ho la seguente classe:Qual è l'ordine ottimale dei membri in una classe?

class Example 
{ 
    bool m_b1; 
    SomeClass m_sc; 
    bool m_b2; 
    char * m_name; 
    bool m_b3; 
    int m_i1; 
    SomeClass * m_sc; 
    int m_i2; 
}; 

Qual è l'ordine ottimale dei membri? Per quanto ne so, l'ordine di dichiarazione dei membri è uguale all'ordine dei membri in memoria, quando si crea un'istanza di questa classe.

  • Devo ordinare i membri in modo che i tipi uguali siano insieme?
  • Tutti i puntatori contano come lo stesso tipo?
  • Il riarrangiamento ha un effetto sulle dimensioni dell'oggetto? Qui si applica l'allineamento a 4 o 8 byte?
  • Come posso vedere gli effetti di quanto sopra? Sizeof mostra la memoria utilizzata da un oggetto che include lo spazio vuoto per l'allineamento?
  • È meglio alla fine della giornata ordinare i membri in modo che il loro significato e il loro contesto siano più facili da comprendere?
+3

A meno che non si sta programmando per un sistema embedded con poca memoria direi che l'ordine non importa molto. Solo se hai array o un * lotto * di variabili membro (nel qual caso direi che il tuo design è sbagliato) in modo che possa causare problemi di cache e il codice sia estremamente time-critical (che di rado è il caso), solo allora dovresti iniziare a pensare al raggruppamento e all'ordine. Inizia dando priorità alla leggibilità (che implica la manutenibilità), e cambia solo se è assolutamente necessario. –

+0

Direi che la dimensione di overlall dell'oggetto ha un effetto sul runtime molto più di quello in cui viene dichiarato il membro. tutti i membri sono eccessi dalla CPU calcolando 'questo + offset' in fase di compilazione, quindi in runtime non c'è molta differenza –

risposta

6

Come regola generale è necessario ordinare in base alle dimensioni, maggiore a minore. Ciò creerà il riempimento minimo della struttura, riducendo così al minimo le dimensioni della struttura. Ciò è più importante se gli oggetti della struttura vengono utilizzati in una memoria allocata contigua, ad es. vettore e aiuta molto con la cache (più oggetti si adattano alla stessa linea della cache).

Un'altra ottimizzazione sorprendente dimostrata da Andrei Alexandrescu (credo fosse in uno di CppCon) è che ha portato per primo il membro più accessibile. Questo è più veloce perché l'offset è zero. Ovviamente stava parlando di micro-ottimizzazione, dopo aver analizzato a fondo l'applicazione e curando ogni piccola dose di prestazioni.

+0

Sai da dove viene l'ordinamento "maggiore-a-piccolo"? Credo che tu abbia le stesse dimensioni per l'ordinamento inverso "da minore a maggiore", in più hai più membri con un piccolo offset. – davidhigh

+0

@davidhigh Non so da dove viene l'ordinamento. Ho sentito da diversi posti (uno dei miei insegnanti, alcune conferenze sul web). Penso che tu abbia ragione, da minore a maggiore darebbe la stessa dimensione. Il "piccolo offset" è irrilevante. L'ottimizzazione deriva dal fatto che l'offset è zero (non da quanto piccolo è l'offset). Sull'ALU, le operazioni con '0' sono più veloci. Penso che anche con '1' (incremento per esempio). Oltre a ciò, l'operando non ha importanza (se è '4',' 10' o '32'). – bolov

3

Devo ordinare i membri in modo che i tipi uguali siano insieme?

Se aumenta la leggibilità, Sì!

Tutti i puntatori contano come lo stesso tipo?

Sì, tutti i puntatori devono prendere o 32 bit o 64 bit o qualsiasi cosa il sistema definisca.

Il riarrangiamento ha un effetto sulle dimensioni dell'oggetto? Si applica l'allineamento a 4 o 8 byte qui?

Ciò è possibile, a causa dell'allineamento. Live example.

È meglio alla fine della giornata ordinare i membri in modo che il loro significato e il loro contesto siano più comprensibili?

Se aumenta significato, leggibilità e manutenibilità, SÌ.

8

L'ordine è importante quando un membro variabile dipende da un altro membro variabile utilizzando elenchi di inizializzazione:

immaginare una classe con due variabile in cui il costruttore della seconda variabile (Varc) richiede il primo (varB)

class A 
{ 
    B varB; 
    C varC; 

    A() 
    : varC(varB) 
    { 
    } 
}; 

L'ordine decide in quali fasi vengono eseguiti i costruttori, pertanto la modifica dell'ordine di varB e varC passerà a varC un oggetto non inizializzato di varB.

Naturalmente, anche lo stile e la leggibilità sono importanti.

+0

Perché il frammento di codice, non funziona. – Niall

+1

Indipendentemente dallo snippet di codice, ritengo che questo punto sia piuttosto buono. –

+0

Spiacente, ho usato il tipo sbagliato di snippet, quindi sembra :) –

1

Una buona regola empirica che ho imparato è "posizionare prima le variabili maggiori".

Nel tuo esempio questo sarebbe

class Example 
{ 

    SomeClass m_sc; 
    SomeClass * m_sc; 
    char * m_name; 
    int m_i1; 
    int m_i2; 
    bool m_b1; 
    bool m_b2; 
    bool m_b3; 
}; 

io non sono il migliore a formulare i miei pensieri, in modo da portare con me.

Le variabili generalmente possono essere posizionate solo in modo che siano allineate con le proprie dimensioni, il che significherebbe che se inseriamo un int tra uno degli ultimi tre valori booleani il compilatore dovrà eseguire il pad sizeof (int) - sizeof (bool) byte) per assicurarsi che i dati si adattino al suo allineamento. Il che significherebbe consumare più memoria del necessario.

Problemi correlati