2012-07-07 17 views
8

Eventuali duplicati:
Is pass-by-value a reasonable default in C++11?Quando dovrei scegliere copia elision passando argomento per riferimento const?

sto leggendo Want Speed? Pass by Value. da Dave Abrahams sulla copia elisione e RVO. E mi chiedo perché abbiamo bisogno della copia elision?

Mi è stato detto troppe volte che dovresti passare gli argomenti della funzione con riferimento const per evitare di copiare (quasi ogni libro C++ che ho letto mi ha detto di questo).

Supponiamo di avere due funzioni:

int f1(const string &s); 
int f2(string s); 

Se l'argomento reale è un rvalue, la copia sarà evitata in entrambe le funzioni. Ma se l'argomento attuale è un lvalue, la copia sarà evitata solo in f1, non in f2. Allora, perché abbiamo bisogno di questa funzionalità?

risposta

10

Passa il valore se è necessaria una copia comunque. Sia che scegliate la firma di f1 o la firma di f2 dipende dal contenuto della funzione. Ad esempio, è possibile utilizzare un riferimento const in questo caso:

int f1(const string& s) { 
    return s.size(); 
} 

Ma si dovrebbe passare dal valore in questo caso:

int f2(string s) { 
    sort(s.begin(), s.end()); 
    s.erase(unique(s.begin(), s.end()), s.end()); 
    return s.size(); 
} 

perché l'alternativa sarebbe questo:

int f2(const string& s) { 
    string temp(s); 
    sort(temp.begin(), temp.end()); 
    temp.erase(unique(temp.begin(), temp.end()), temp.end()); 
    return temp.size(); 
} 
+1

Una nota: il secondo caso spesso si verifica nei costruttori. Dato 'struct S {S (...): s (s) {} std :: string s; }; ', allora è meglio usare' std :: string s' al posto di '...' piuttosto che un 'std :: string const & s' dato che ci sarà comunque una copia. –

+2

@MatthieuM: Ma assicurati di spostarlo nel membro, non copiarlo. cioè 'S (std :: string s): s (std :: move (s)) {}' –

1

RVO non si applica all'esempio poiché il valore restituito è int.

string f1(const string &s) { 
    string ret = s; // always makes a copy 
    ret += 'x'; 
    return ret; // makes a copy pre-C++11 if no RVO 
} 

Tally: 1-2 copie in C++ 03, esattamente 1 in C++ 11 plus (se elision è disattivato) una mossa che può degenerare a una copia per qualche altra classe che std::string.

string f2(string s) { // calling makes a copy if lvalue or no elision 
    s += 'x'; 
    return s; // makes a copy pre-C++11 if no RVO 
} 

Tally: 0-2 copie in C++ 03 o 0-1 in C++ 11.

Come altri hanno detto, passa per valore quando si desidera manipolare l'oggetto come un valore puro, senza alcuna semantica di riferimento.

const & è un idioma familiare, ma è un po 'scomodo in termini di semantica del linguaggio. Lo usi quando non vuoi affatto un riferimento; il & serve solo a rendere significativo il const nella definizione del parametro. Se si desidera modificare il parametro (ma solo localmente), allora lo const non si applica realmente e anche lo & si disattiva.

0

f2 segnali con la sua firma, non importa quello che mi passi, mi occuperò della mia copia del tuo oggetto. Utile, se f2 sta per modificare l'oggetto in modo non reversibile (ad esempio rubare le risorse spostando) o in alcuni scenari di concorrenza. C++ 11 aggiunge un nuovo livello di confusione al (già confuso) sistema di tipo C++ ma una volta che ci si pensa ha molto senso ...