c++ c++11 move-semantics

c++ - Si muevo un objeto local a una función, ¿seguirá siendo válido después?



c++11 move-semantics (4)

El código es válido, porque no se realiza ningún movimiento real. Aquí es cómo podría hacer que sea inválido:

string f(std::string&& s) { std::string res(std::move(s)); res += " plus extra"; return res; }

El estado de str después de esta llamada sería válido, pero no especificado. Esto significa que aún podría asignar un nuevo valor a str para volver a ponerlo en un estado válido, pero no podría emitirlo sin invocar un comportamiento no especificado ( demo ). Consulte esta sección de preguntas y respuestas para obtener información específica sobre el estado de mudanza.

Por lo tanto, esto proporciona la salida prevista:

void f(std::string&& s) { s += " plus extra"; } int main(void) { std::string str = "A string"; f( std::move(str) ); std::cout << str << std::endl; return 0; }

Una cuerda más extra

Es decir, funciona cuando lo ejecuto en Ideone, pero ¿es UB? La adición de inicializaciones de cadena adicionales antes y después de la llamada a f no cambió nada.


Es válido, no UB.

También es un código horriblemente ofuscado. std::move(s) no es más que una conversión a rvalue. Por sí mismo no genera ningún código en absoluto. Su único propósito es convertir un lvalue en un rvalue para que el código del cliente pueda sobrecargarse en las expresiones lvalue / rvalue (de string en este caso).

Debes pasar por lvalue-reference para este caso:

void f(std::string& s) { s += " plus extra"; } ... f( str );

O alternativamente, pase por valor y devuelva una nueva cadena:

std::string f(std::string s) { s += " plus extra"; return s; } ... str = f( std::move(str) );


std::move es simplemente convertir su objeto en una referencia de valor. Ya que su función toma la referencia y solo hace algo con ella, aquí no se toma posesión, por lo que su cadena aún se encuentra en un estado válido y se puede usar de manera segura.

No recomendaría usar esto en su código porque es engañoso, ya que mucha gente consideraría que su cadena no es válida, ya que la apropiación es el uso principal de la referencia rvalue, por lo tanto, std::move .

Si realmente necesita llamar a esta función de esta manera, le recomendaría que escriba esto:

std::string myString{"a string"}; // leave a comment here to explain what you are doing. f(static_cast<std::string&&>(myString));

Sin embargo, tenga en cuenta que su ejemplo sería realmente diferente si la función f tomara valor en lugar de una referencia. En ese caso, llamarlo con std::move o static_cast invalidaría la cadena.


std::move no mueve nada. Indica que un objeto puede ser " movido de ", mediante la conversión de su argumento a un valor de r .

Su código es válido y no se realiza ninguna operación de movimiento.

Obtendría el comportamiento donde el estado de str no está especificado después de llamar a f() , si mueve-construye otro objeto de cadena desde s . El constructor de movimiento realiza la operación de movimiento real.

Ejemplo:

std::vector<std::string> sv; void f(std::string&& s) { s += " plus extra"; sv.push_back(std::move(s)); // move s (str) into a new object } int main(void) { std::string str = "A string"; f(std::move(str)); std::cout << str << std::endl; // output: empty string std::cout << sv.back() << std::endl; // output: "A string plus extra" return 0; }