[c++] C ++ 11 valores y confusión de semántica de movimiento (declaración de retorno)



Answers

Ninguno de ellos copiará, pero el segundo se referirá a un vector destruido. Las referencias con nombre de rvalue casi nunca existen en el código normal. Usted escribe exactamente cómo habría escrito una copia en C ++ 03.

std::vector<int> return_vector()
{
    std::vector<int> tmp {1,2,3,4,5};
    return tmp;
}

std::vector<int> rval_ref = return_vector();

Excepto ahora, el vector se mueve. El usuario de una clase no se ocupa de sus referencias de valores en la gran mayoría de los casos.

Question

Estoy tratando de entender las referencias de valores y mover la semántica de C ++ 11.

¿Cuál es la diferencia entre estos ejemplos, y cuál de ellos va a hacer ninguna copia vectorial?

Primer ejemplo

std::vector<int> return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return tmp;
}

std::vector<int> &&rval_ref = return_vector();

Segundo ejemplo

std::vector<int>&& return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return std::move(tmp);
}

std::vector<int> &&rval_ref = return_vector();

Tercer ejemplo

std::vector<int> return_vector(void)
{
    std::vector<int> tmp {1,2,3,4,5};
    return std::move(tmp);
}

std::vector<int> &&rval_ref = return_vector();



No es una respuesta per se , sino una guía. La mayoría de las veces no tiene mucho sentido declarar variables T&& locales (como lo hizo con std::vector<int>&& rval_ref ). Aún tendrá que std::move() para usar en los métodos de tipo foo(T&&) . También está el problema que ya se mencionó que cuando intente devolver tal rval_ref de la función obtendrá el estándar referencia-a-destruido-temporal-fiasco.

La mayoría de las veces me gustaría seguir el siguiente patrón:

// Declarations
A a(B&&, C&&);
B b();
C c();

auto ret = a(b(), c());

No tiene ninguna referencia a los objetos temporales devueltos, por lo que evita el error del programador (inexperto) que desea usar un objeto movido.

auto bRet = b();
auto cRet = c();
auto aRet = a(std::move(b), std::move(c));

// Either these just fail (assert/exception), or you won't get 
// your expected results due to their clean state.
bRet.foo();
cRet.bar();

Obviamente hay casos (aunque bastante raros) en que una función realmente devuelve un T&& que es una referencia a un objeto no temporal que puede mover a su objeto.

En cuanto a RVO: estos mecanismos generalmente funcionan y el compilador puede evitar fácilmente la copia, pero en los casos donde la ruta de retorno no es obvia (excepciones, if condicionales determinan el objeto nombrado que devolverá, y probablemente pares otros) rrefs son sus salvadores (incluso si potencialmente más caro).




Related