2010-09-19 6 views
5

Se si dispone di una classe che ha molte, float e enum variabili membro, è considerato efficiente e/o buona pratica restituirle come riferimenti anziché come copie e restituire riferimenti costanti in cui non devono essere apportate modifiche? O c'è una ragione per cui dovrei restituirli come copie?È consigliabile restituire sempre i riferimenti per i getter della variabile membro?

+1

Ho fatto una domanda correlata http://stackoverflow.com/q/3740876/15161 - forse le risposte ci aiuteranno. – slashmais

+0

Domanda sbagliata. Migliore domanda: [È una cattiva idea avere getter di tutti i tuoi dati membri?] (Http://www.idinews.com/quasiClass.pdf) – sbi

risposta

7

Non vi è alcun motivo per restituire tipi primitivi come int e float per riferimento, a meno che non si desideri consentire loro di essere modificati. Restituirli per riferimento è in realtà meno efficiente perché non salva nulla (int s ei puntatori di solito hanno le stesse dimensioni) mentre il dereferenziamento aggiunge effettivamente un sovraccarico.

+0

E 'stato utile, grazie! – Jengerer

+0

Ho una domanda, però. Quale dovrebbe essere considerato un giusto compromesso per l'utilizzo di un puntatore o di un riferimento? Ad esempio, un doppio è di 8 byte e un puntatore a un doppio è di 4 byte. Il sovraccarico aggiunto per il dereferenziamento supera le dimensioni inferiori? – Jengerer

+1

Sì. La mia regola generale è di restituire direttamente i tipi primitivi, anche 'double'. Le classi vengono restituite come riferimenti const, anche piccoli. –

1

Questo è probabilmente per lo più una questione di stile o preferenza. Una ragione per non restituire riferimenti è perché stai usando getter e setter per permetterti di cambiare l'implementazione di quei membri, se hai cambiato un membro privato in un altro tipo, o lo hai rimosso completamente perché può essere calcolato, allora non hai più la possibilità di restituire un riferimento, poiché non c'è nulla a cui fare riferimento.

D'altra parte, restituire riferimenti per tipi non banali (classi composte) può velocizzare il codice un po 'per fare una copia, e puoi consentire a quei membri di essere assegnati attraverso il riferimento restituito (se lo si desidera).

4

Se sono riferimenti costanti, forse è OK. Se non sono riferimenti costanti, probabilmente no.

Per quanto riguarda l'efficienza - su una macchina a 64 bit, i riferimenti saranno quantità a 64 bit (puntatori sotto mentite spoglie); int e float e enum saranno più piccoli. Se restituisci un riferimento, stai forzando un livello di riferimento indiretto; è meno efficiente.

Pertanto, in particolare per i tipi predefiniti come valori di ritorno, è generalmente preferibile restituire il valore anziché un riferimento.

+0

Grazie per la risposta, ha aiutato! – Jengerer

4

Alcuni casi è necessario:

Guarda sovraccaricato operator[] per qualsiasi classe. Di solito ha due versioni. La versione mutante deve restituire un riferimento.

int &operator[](int index);   // by reference 
int operator[](int index) const;  // by value 

In generale, è consentito consentire l'accesso ai membri della classe da parte di entità attendibili da una classe, ad es. amici. Nel caso in cui queste entità fidate abbiano anche bisogno di modificare lo stato, i riferimenti o i puntatori ai membri della classe, sono le uniche opzioni disponibili.

In molti casi, i riferimenti di solito semplificano la sintassi ad esempio dove 'v' è vettore STL.

v.at(1) = 2 vs *(v.at(1)) = 2; 
0

Quasi, i riferimenti const sono migliori. Per intelli e simili non c'è motivo perché vorreste che fossero cambiati o perché hanno la stessa dimensione (o quasi) di un riferimento.

Quindi sì, è una buona idea. Preferisco un'altra lingua o per hackerare la mia roba in C++ e solo permettere alla var di essere pubblica (ancora una volta è solo la mia roba)

+0

Certo, potrei renderli pubblici, ma alcuni di essi non dovrebbero essere accessibili pubblicamente poiché hanno determinate restrizioni per il valore che possono essere dati, e quindi li avvolgo con setter/getter per far rispettare quelle regole. Grazie per la risposta! – Jengerer

+0

@Jenger: per regole molto semplici e autonome, puoi consentire al sistema di tipi di aiutarti. Ad esempio, invece di un campo 'int digit' e un setter che controlla che le cifre siano tra 0 e 9, potresti scrivere il tuo tipo' digit' che ha solo i valori da 0 a 9 e quindi usa un campo 'digit' pubblico nella tua classe, senza getter e setter. – fredoverflow

+0

Jengerer: Sto dicendo che nel mio codice a casa lo farò dappertutto perché è mio e nessun altro (nessuno deve toccarlo). Inoltre, se la lezione è banale, lo farò al lavoro e, in effetti, nessuno si è lamentato. Ma non lavoro davvero sul C++ –

0

Questa è una domanda di prestazioni, ma per lo più da un punto di vista della robustezza direi è preferibile restituire valori anziché riferimenti const. Il motivo è che anche i riferimenti const indeboliscono l'incapsulamento.Considera questo:

struct SomeClass 
{ 
    std::vector<int> const & SomeInts() const; 
    void AddAnInt (int i); // Adds an integer to the vector of ints. 
private: 
    std::vector<int> m_someInts; 
}; 

bool ShouldIAddThisInt(int i); 

void F (SomeClass & sc) 
{ 
    auto someInts = sc.SomeInts(); 
    auto end = someInts.end(); 
    for (auto iter = someInts.begin(); iter != end; ++iter) 
    { 
     if (ShouldIAddThisInt(*iter)) 
     { 
     // oops invalidates the iterators 
     sc.AddAnInt (*iter); 
     } 
    } 
} 

Quindi nel caso abbia senso semanticamente e possiamo evitare allocazioni dinamiche eccessive, preferisco il ritorno per valore.

0

I getter sono per le emissioni di una classe dire Exhaust Car.emit(), dove l'auto ha appena creato il Exhaust.

Se si sono tenuti a scrivere const Seat& Car.get_front_seat()
di avere in seguito sedersi in Driver, si può notare subito che qualcosa non va.
correcly, si preferisce scrivere Car.get_in_driver(Driver)
che poi chiama direttamente seat.sit_into(Driver).

Questo secondo metodo evita facilmente quelle situazioni imbarazzanti quando si è get_front_seat ma la porta è chiusa e praticamente si spinge il guidatore attraverso la porta chiusa. Ricorda, hai solo chiesto un posto! :)

Tutto sommato: restituire sempre in base al valore (e fare affidamento sull'ottimizzazione del valore restituito), o rendersi conto che è ora di cambiare il progetto.

Lo sfondo: le classi sono state create in modo che i dati possano essere accoppiati con la sua funzionalità di accesso, localizzando bug ecc. Quindi le classi non sono mai attività, ma orientate ai dati.

Ulteriori insidie: in C++ se si restituisce qualcosa con const ref, quindi si può facilmente dimenticare che è solo un riferimento e una volta che il tuo oggetto è stato distrutto puoi essere lasciato con un riferimento non valido. Altrimenti, quell'oggetto verrà copiato una volta che lascia comunque il getter. Ma le copie non necessarie vengono evitate dal compilatore, vedere Return Value Optimization.

Problemi correlati