2012-07-07 18 views
8

Duplicar posible:
Is pass-by-value a reasonable default in C++11?¿Cuándo debería elegir copiar elisión sobre pasar el argumento por const reference?

estoy leyendo Want Speed? Pass by Value. por Dave Abrahams sobre la elisión de copia y RVO. Y me pregunto por qué necesitamos la elisión de copia.

Se me ha dicho demasiadas veces que debe pasar los argumentos de la función por referencia para evitar copiar (casi todos los libros en C++ que leí me contaron sobre esto).

Supongamos que tenemos dos funciones:

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

Si el argumento actual es un valor de lado derecho, la copia se puede evitar en ambas funciones. Pero si el argumento real es un valor l, solo se evitará copiar en f1, no en f2. Entonces, ¿por qué necesitamos esta característica?

Respuesta

10

Pase el valor si necesita una copia de todos modos. Si elige la firma de f1 o la firma de f2 depende del contenido de la función. Por ejemplo, se utilizaría una referencia constante en este caso:

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

Pero le paso por valor, en este caso:

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

porque la alternativa sería la siguiente:

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: este último caso a menudo ocurre en los constructores. Dada 'struct S {S (...): s (s) {} std :: string s; }; ', entonces es mejor usar' std :: string s' en lugar de '...' en lugar de 'std :: string const & s' ya que habrá una copia de todos modos. –

+2

@MatthieuM: Pero asegúrese de moverlo al miembro, no copiarlo. es decir 'S (std :: string s): s (std :: mover (s)) {}' –

1

RVO no se aplica a su ejemplo porque el valor de retorno es 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 copias en C++ 03, exactamente 1 en C++ 11 más (si se desactiva la elisión) un movimiento que puede degenerar en una copia de alguna otra clase de 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 copias en C++ 03, o 0-1 en C++ 11.

Como han dicho otros, pase el valor cuando desee manipular el objeto como un valor puro, sin ninguna semántica de referencia.

const & es un modismo familiar, pero es un poco complicado en términos de semántica del lenguaje. Lo usas cuando no quieres una referencia; el & solo sirve para hacer que el const tenga sentido en la definición del parámetro. Si desea modificar el parámetro (pero solo localmente), entonces const no se aplica realmente, y también se elimina el &.

0

f2 señales por su firma, no importa lo que me pase, me ocuparé de mi propia copia de su objeto. Útil, si f2 va a modificar el objeto de una manera no reversible (por ejemplo, robarle sus recursos moviéndolo), o en algunos escenarios de simultaneidad. Es cierto que C++ 11 agrega un nuevo nivel de confusión al (ya confuso) sistema de tipo C++, pero una vez que lo piensas tiene mucho sentido ...

Cuestiones relacionadas