todas resueltos programacion orientada objetos las funciones ejercicios ejemplos codigo clases c++ function c++11 move-semantics rvalue-reference

resueltos - programacion orientada a objetos c++ ejemplos



¿Es posible:: mover objetos de las funciones?(C++ 11) (2)

Este programa intenta mover una cadena de una función y usarla para la construcción de otra cadena:

#include <iostream> #include <string> #include <utility> std::string && Get_String(void); int main(){ std::string str{Get_String()}; std::cout << str << std::endl; return 0; } std::string && Get_String(void){ std::string str{"hello world"}; return std::move(str); }

El programa compila, pero segfaults en la ejecución.

Este fue mi razonamiento: Get_String creará una cadena local. Se deberá hacer una copia de esa cadena y devolverla antes de que la cadena quede fuera del alcance. Esa copia se usará para construir la cadena en main. Sin embargo, si moví la cadena fuera de la función, no se necesitaría hacer ninguna copia.

En un intento de comprender la semántica de los movimientos, alguien podría explicar por qué lo que estoy haciendo, probablemente no tenga sentido. ¿Es posible mover objetos fuera de una función?

EDITAR:
Se compila y se ejecuta correctamente si cambio la firma de la función de:

std::string && Get_String(void);

a

std::string Get_String(void);

¿Es aún más eficiente mover la cuerda durante el retorno en este caso?


Esa función Get_String vincula una referencia rvalue a un objeto local de función. Las referencias de Rvalue son útiles para cosas que están a punto de destruirse, pero tan malas como las referencias de valor para cosas que ya han sido destruidas.

Para mover un objeto local fuera de una función, simplemente regresa por tipo de clase:

std::string Get_String(void) { std::string str{"hello world"}; return str; }

Si el compilador no logra eliminar por completo la copia / movimiento, el valor de retorno que obtiene el llamante se construirá utilizando un constructor de movimiento, no un constructor de copia, siempre que la expresión de retorno sea:

  • un temporal, o
  • un único identificador que nombra algo con una duración de almacenamiento automática (como str antes), o
  • std::move(something)

(Por lo tanto, aún podría tener return std::move(str); para ser explícito, pero no es necesario aquí).


Dado este ejemplo,

X foo () { X x; return x; }

el siguiente comportamiento está garantizado:

• Si X tiene una copia accesible o un constructor de movimiento, el compilador puede elegir eludir la copia. Esta es la denominada optimización del valor de retorno (denominada) ((N) RVO), que se especificó incluso antes de C ++ 11 y es compatible con la mayoría de los compiladores.
• De lo contrario, si X tiene un constructor de movimiento, x se mueve.
• De lo contrario, si X tiene un constructor de copia, x se copia.
• De lo contrario, se emite un error en tiempo de compilación.

Tenga en cuenta también que devolver una referencia rvalue es un error si el objeto devuelto es un objeto local no estático:

X&& foo () { X x; return x; // ERROR: returns reference to nonexistent object }

Una referencia de valor real es una referencia, y devolverla mientras se refiere a un objeto local significa que usted devuelve una referencia a un objeto que ya no existe. Si std::move() se usa no importa.

std::move() realmente no mueve el objeto; solo convierte lvalues ​​en valores.