Usted debe preferir pase por valor si va a hacer una copia con los valores no móviles. Por ejemplo, su versión const&
de WriteDefaultFileOutput
copia explícitamente el parámetro, luego mueve la copia con la versión mover. Lo que significa que si se llama a WriteDefaultFileOutput
con un valor móvil (valor xo prvalue), se moverá y si se llama con un valor l, se copiará.
Esto significa que hay no diferencia entre las dos formas de esta función. Considere esto:
WriteDefaultFileOutput(L"SomeString");
En el primer caso, se creará un temporal wstring
. Las temporarias son valores prvariedades, por lo que se "moverán" al parámetro (dado que wstring
tiene un constructor de movimiento). Por supuesto, cualquier compilador que se precie saldrá del movimiento y simplemente construirá el temporal directamente en el parámetro.
En su segundo caso, sucede más o menos lo mismo. Se crea un wstring
temporal. Los temporarios son valores prvaluados, por lo que pueden enlazarse a los tipos de parámetros &&
. Por lo tanto, llamará a la primera versión de su función con una referencia de valor r al temporal. La única diferencia posible sería un compilador que no elide el movimiento. E incluso entonces, una mudanza no es tan costosa (dependiendo de su implementación basic_string
).
ahora esto:
std::wstring myStr{L"SomeString"};
WriteDefaultFileOutput(myStr);
En el primer caso, la llamada a WriteDefaultFileOutput
causará una copia del valor myStr
en el parámetro de la función.
En el segundo caso, myStr
es un lvalue. Es no se puede se unen a un parámetro &&
. Por lo tanto, la única versión que puede llamar es la versión const&
. Esa función construirá manualmente una copia, y luego moverá la copia con la otra.
Un efecto idéntico. Su primera versión tiene menos código, así que vaya con eso por razones obvias.
En general, yo diría que sólo hay dos razones para tomar un parámetro como &&
:
- Estás escribiendo un constructor movimiento.
- Está escribiendo una función de reenvío y necesita un reenvío perfecto.
En todos los demás casos en los que desee que el movimiento sea posible, simplemente tome un valor. Si el usuario quiere copiar, déjelos copiar. Supongo que si quieres prohibir explícitamente la copia del parámetro, puedes tomar un &&
. Pero el problema principal es uno de claridad.
Si toma un parámetro de valor y el usuario proporciona un valor móvil, entonces el valor proporcionado por el usuario será siempre se moverá. Por ejemplo, su versión &&
de WriteDefaultFileOutput
no tiene tiene para mover realmente los datos de su parámetro. Ciertamente puede. Pero no tiene por qué. Si tomó un valor, entonces ya habría reclamado los datos.
Por lo tanto, si una función toma un parámetro de valor, y se ve un std::move
en ese valor, entonces usted sabe que el objeto que se movía está vacía. Se ha movido .
El wstring tiene un constructor de movimiento, ¿no es esto lo que ya está sucediendo? –
¿No se puede evitar el tmp y el std :: mover y pasar wstring (destino) directamente en la llamada a la función? – juanchopanza
Esta es quizás una pregunta estúpida, pero ¿por qué no es una opción pasar una referencia de referencia normal normal? Escribir algo (aquí: una cadena) en una transmisión no debería modificarlo ni requerir una copia privada adicional. Entonces, realmente no veo el razonamiento detrás de hacer una copia temporal (posiblemente profunda) y luego usar semánticas de movimiento (destructivas) en el temporal. Excepto por el uso de la semántica de movimientos, por supuesto. – Damon