2013-09-06 19 views
7

C'è a set of good rules to determine whether pass by value or const referencePassaggio per valore o riferimento const?

  • Se la funzione intende modificare l'argomento come effetto collaterale, prendere facendo riferimento non-const.
  • Se la funzione non modifica il suo argomento e l'argomento è del tipo primitivo , prenderlo in base al valore.
  • Altrimenti prendere il riferimento const, ad eccezione dei seguenti casi : Se la funzione dovrebbe quindi eseguire comunque una copia del riferimento const , prenderla per valore.

Per il costruttore come segue, come determinarlo?

class A 
{ 
public: 
    A(string str) : mStr(str) {} // here which is better, 
           // pass by value or const reference? 

    void setString(string str) { mStr = str; } // how about here? 

private: 
    string mStr; 
}; 
+2

Il costruttore è in media migliore di quello che si ha con 'mStr (std :: move (str))'. Se hai davvero bisogno di ottimizzarlo di più, puoi comunque sovraccaricarlo. – chris

+0

Devi comunque prenderne una copia, vero? –

+0

@chris Penso che il tuo metodo 'move' funzioni anche per' setString'. Se 'string' non ha ctor e assegnamento, qual è il modo migliore? Grazie. – user1899020

risposta

3

L'articolo che sito è non un buon riferimento per il software ingegneria. (E 'anche probabile obsoleto, dato che parla di semantica mossa ed è datato 2003.)

La regola generale è semplice: passare tipi di classe per riferimento const, e di altri tipi per valore. Ci sono delle eccezioni esplicite: in tenendo conto delle convenzioni della libreria standard, è anche solito passare gli iteratori e gli oggetti funzionali in base al valore.

Qualsiasi altra cosa è l'ottimizzazione, e non dovrebbe essere intrapresa fino al che il profiler dice che è necessario.

0

In questo caso è meglio passare argomento per riferimento const. Motivo: la stringa è un tipo di classe, non lo si modifica e può essere arbitrario.

+0

Cura spiegare perché? –

+4

Non sono d'accordo; se stai copiando (o spostando) l'argomento comunque e [vuoi la velocità, passa per valore] (http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/). – Angew

+0

@Angew, quel link sembra rotto. Ottengo un errore del database. – patrickvacek

3

In questo caso particolare, e presupponendo C++ 11 e sposta costruzione/assegnazione per le stringhe, è necessario prendere l'argomento per valore e spostare per il membro per il costruttore.

A::A(string str) : mStr(std::move(str)) {} 

Il caso del setter è un po 'più complicato e io non sono sicuro se si vuole veramente/necessità di ottimizzare ogni bit di esso ... Se si desidera ottimizzare il massimo che potrebbe fornire due overload, uno prendendo un riferimento di rvalue e un altro prendendo un riferimento di const-value. In ogni caso, il riferimento lvalue const è probabilmente un buon approccio abbastanza:

void A::setString(string const& str) { mStr = str; } 

Perché la differenza?

Nel caso del costruttore, il membro non è ancora stato creato, quindi sarà necessario allocare memoria. È possibile spostare l'allocazione di memoria (e la copia effettiva dei dati, ma questo è il costo del leaser) nell'interfaccia, in modo che se il chiamante ha un temporaneo può essere inoltrato senza un'assegnazione di memoria aggiuntiva.

In caso di assegnazione le cose sono un po 'più complicate. Se la dimensione corrente della stringa è abbastanza grande da contenere il nuovo valore, non è richiesta alcuna allocazione, ma se la stringa non è sufficientemente grande, sarà necessario riallocare. Se l'allocazione viene spostata nell'interfaccia (argomento per valore), verrà eseguita sempre anche quando non è necessario. Se l'allocazione viene eseguita all'interno della funzione (argomento di riferimento const), per un piccolo insieme di casi (quelli in cui l'argomento è un temporaneo che è maggiore del buffer corrente) verrà eseguita un'allocazione che altrimenti sarebbe stata evitata.

1

È sempre meglio utilizzare l'elenco di inizializzazione di membri per inizializzare i vostri valori in quanto fornisce i seguenti vantaggi:

1) La versione assegnazione, crea un costruttore predefinito per inizializzare MSTR e poi assegnato un nuovo valore su all'inizio di quello predefinito. L'uso del MIL evita questa sprecata costruzione perché gli argomenti nella lista sono usati come argomenti del costruttore.

2) È l'unico posto in cui è possibile inizializzare le variabili costanti a meno che non si tratti di interger che è possibile utilizzare nella classe.enum T {v = 2};

3) È il punto di inizializzazione dei riferimenti.

Questo è quello che vorrei suggerire:

#include <iostream> 
#include <string> 

class A 
{ 
    private: 
     std::string mStr; 

    public: 
     A(std::string str):mStr(str){} 

     //if you are using an older version of C++11, then use 
     //std::string &str instead 
     inline const void setString(std::string str) 
     { 
     mStr = str; 
     } 

     const std::string getString() const 
     { 
     return mStr; 
     } 
}; 

int main() 
{ 
    A a("this is a 1st test."); 

    a.setString("this is a 2nd test."); 

    std::cout<<a.getString()<<std::endl; 
} 

Date un'occhiata a questo: http://www.cplusplus.com/forum/articles/17820/

Spero che questo cancella le cose per voi. Cos

Problemi correlati