2016-01-27 14 views
6

Sono consapevole delle differenze tra passaggio per valore, riferimento o puntatore nel caso generale. Tuttavia, la mia domanda riguarda il caso speciale di un contenitore con struttura semplice.Passaggio di container per valore o per riferimento

Assumendo questo caso:

class image{ 
    image()=default; 
    image(image const&)=default; 
    ~image()=default; 

    int w; 
    int h; 
    uchar* data; 
} 

Quando si passa un oggetto di questa classe quanto copiato sono solo due numeri interi e non puntatore l'intero dati. In questo caso c'è lo scopo di passarlo per riferimento? O c'è uno scopo di non passarlo per riferimento?

La cosa che ha fatto scattare questa domanda è che ho letto che iterators in C++ sono stati progettati per essere leggeri e per essere passati per valore. Quindi, penso che questo concetto possa essere applicato a classi che rappresentano un contenitore per i dati reali senza dati.

+1

Che cosa significa 'uchar * data'? Voglio dire, è una risorsa da copiare e pulire in profondità? – Jarod42

+0

durante la copia (non la clonazione) verrà copiato solo il puntatore e entrambi gli oggetti condivideranno gli stessi dati effettivi –

+0

correlati: http://stackoverflow.com/questions/4172722/questo-è-la-rolla-di-store –

risposta

6

Imho, le migliori linee guida su come passare argomenti possono essere trovate in Herb Sutters talk eccellente Back to the Basics! Essentials of Modern C++ Style. Nel tuo caso particolare, passare per valore sarebbe l'opzione migliore, dato che la tua struttura è economica da copiare.

cpp parameter passing overview.

+0

Si potrebbe anche obiettare che questa struttura è anche "economica da spostare" - specialmente se ha un puntatore gestito come "unique_ptr" che è garantito per supportare lo spostamento correttamente e suggerisce di passarlo per riferimento. Penserei che questo particolare esempio sia così piccolo che entrambi gli argomenti/le decisioni sono ugualmente validi. – CompuChip

+0

Non è solo il costo di copia che è importante; gli oggetti distinti ottengono più opportunità di ottimizzazione perché il compilatore può supporre che nient'altro possa puntare/riferirsi a quell'oggetto. Ad esempio: ' int gi; int val (int i) { \t gi + = i; \t gi + = i; \t return i; } int ref (const int & i) { \t gi + = i; \t gi + = i; \t ritorno i; } int main() { \t gi = 2; \t std :: cout << val (gi) << std :: endl; // outputs 2 \t gi = 2; \t std :: cout << ref (gi) << std :: endl; // output 8 } ' In ref(), il compilatore non può assumere il valore di i non cambia. – Nevin

5

Con il costruttore di copie predefinito, qualsiasi copia sarà superficiale e non farà una copia della memoria puntata da a entro il data. Pertanto, quando si passa per riferimento, verranno passati solo i due numeri interi e il puntatore, per un totale di circa 12 bytes (a seconda dell'architettura, dimensione del puntatore).

Questa differenza è così piccola che non importa se lo si passa per valore o per riferimento. Quest'ultimo può essere leggermente più veloce perché il puntatore può essere probabilmente sempre passato tramite un registro CPU ei 12 byte potrebbero non essere, ma questa è davvero una micro-ottimizzazione.

Personalmente passo tutto tranne i tipi primitivi tramite il riferimento (const), per impostazione predefinita, a meno che non abbia un motivo per non farlo (vedere jupp0r's answer). Il vantaggio principale durante lo sviluppo è che man mano che la classe cresce non devo preoccuparmi di quando diventa troppo grande e cambiare tutte le mie funzioni per passare per riferimento.

Per quanto riguarda gli iteratori C++ predefiniti: notare che sono che significa semplicemente essere solo indicatori. Infatti, so che per la compilazione di Microsoft Visual C++ in modalità Release con le ottimizzazioni abilitate, gli iteratori per strutture di dati contigue come std::vector si ridurranno proprio a questo. Non sono a conoscenza se anche altri compilatori lo fanno, lo penserei. Tuttavia noterete che se disabilitate le ottimizzazioni, improvvisamente vi è una differenza tra la scrittura di it++ e ++it in incrementi di loop, ad esempio - semplicemente a causa dell'operazione di copia aggiuntiva nel primo caso. Quindi anche "economico da copiare" potrebbe avere un impatto se lo si fa abbastanza spesso. Come al solito: quando sei preoccupato per le prestazioni, misura e decidi in base ai numeri.

+0

Gli iteratori per qualcosa di diverso dalle strutture di dati contigui non possono ridursi ai soli puntatori, poiché hanno una semantica diversa. – Nevin

+0

Grazie a @Nevin, modificato. – CompuChip