Si nunca vuelve a hacer referencia a esa variable, ¿el compilador puede moverla al objeto de función resultante?
No. La única situación en la que el compilador puede reemplazar una copia con un movimiento son exactamente las mismas situaciones en las que se permite realizar una elisión de copia. Estas situaciones incluyen devolver un objeto local por valor o inicializar un objeto con un valor temporal. En estos casos, el compilador puede eludir la copia haciendo que el origen y el objetivo sean el mismo objeto. Si el compilador no puede hacer eso por la razón que sea, tiene que considerar el objeto fuente como un valor r con respecto a la resolución de sobrecarga para seleccionar el constructor apropiado para el objeto objetivo. En su caso, sin embargo, el archivo es un Lvalue y ninguno de los casos anteriores se aplica. Deberías usar un movimiento explícito.
Desafortunadamente, C++ 11 no tiene una sintaxis para una "captura de movimiento". En mi humilde opinión, es una pena. Pero std :: bind es compatible con esto. Debería ser posible combinar std :: unen con una expresión lambda como esto:
void foo(char const* p) {
string s = p;
auto fun = bind([](string const& s){
...
},move(s));
fun();
}
para que la cadena se mueve en el objeto función.
Si la intención de llamar a esta función sólo una vez y desea mover la cuerda fuera del objeto de la función de nuevo, puede utilizar una referencia no const:
void foo(char const* p) {
string s = p;
auto fun = bind([](string & s) {
some_other_func(move(s));
},move(s));
fun();
}
Tenga en cuenta que, si no lo hace desee utilizar unen aquí, pero dejar que el constructor del objeto lambda crear una copia de s, moviendo la cuerda hacia fuera del objeto función requiere la palabra clave mutable:
void foo(char const* p) {
string s = p;
auto fun = [=]() mutable {
// ^^^^^^^
some_other_func(move(s));
};
fun();
}
porque de lo contrario el operador del tipo de cierre() función será const- calificado que a su vez hace s
una cadena constificada.
En C++ 14 la cláusula de captura lambda se volvió un poco más flexible. Ahora podemos escribir
void foo(char const* p) {
string s = p;
auto fun = [s=move(s)]() mutable { // #1
some_other_func(move(s)); // #2
};
fun();
}
donde # 1 se mueve el valor de cadena en un objeto lambda y # 2 se mueve la cadena de valor fuera (dependiendo de cómo some_other_func
se declara exactamente).
Supongo que esto es demasiado difícil de entender en general para los compiladores. ¿Puedes proporcionar un código de ejemplo? – fredoverflow
Existe la regla "como si", por supuesto. Pero supongo que estás pensando en un caso en el que el copiador y/o el dispositivo móvil tengan efectos secundarios, por lo que puedes notar la diferencia. Interesante pregunta. – aschepler
@aschepler: si recuerdo correctamente, el compilador puede ignorar los efectos secundarios de copiar y mover constructores. @DeadMG: me parece que podría ser optimizado, ¿lo has probado? –