c++ - ¿Por qué los enlaces estructurados deshabilitan RVO y mueven en la declaración de retorno?
c++11 c++17 (1)
Sin embargo, ¿por qué el movimiento implícito NO se puede esperar tampoco?
Por la misma razón por la que elision está desactivado: porque es una referencia , no el nombre de un objeto independiente. Cada uso de second
es esencialmente equivalente a decir obj.whatever
o get<1>(obj)
(aunque en este último caso, almacenamos la referencia). Y no hay movimiento implícito de ninguna de esas expresiones.
El enlace estructurado es para acceder a subobjetos del objeto dado. No se pueden omitir devoluciones de subobjetos, ni se puede mover implícitamente de ellos. Por lo tanto, no puede evitar los nombres de enlace estructurado ni moverlos implícitamente.
Supongamos que tenemos una clase llamada AAA
que admite tanto copiar / mover :
class AAA
{
public:
AAA() = default;
~AAA() = default;
AAA(const AAA& rhs)
{
std::cout << "Copy constructor" << std::endl;
}
AAA(AAA&& rhs)
{
std::cout << "Move constructor" << std::endl;
}
};
En el siguiente código, get_val
devuelve el second
:
AAA get_val()
{
auto [ first, second ] = std::make_tuple(AAA{}, AAA{});
std::cout << "Returning - " << std::endl;
return second;
}
auto obj = get_val();
std::cout << "Returned - " << std::endl;
Ahora se copia el second
, imprimiendo la siguiente salida:
...
Returning -
Copy constructor
Returned -
Esto es desafortunado, porque mi expectativa del resultado es que no hay una llamada para copiar el constructor, o al menos se movió implícitamente .
Para evitar copiar, tendré que aplicar explícitamente std::move
en él.
return std::move(second);
Entonces recibiría el resultado de:
...
Returning -
Move constructor
Returned -
Supongo que la razón por la que RVO no se ejecuta es que probablemente los compiladores verían el second
como una referencia, mientras que get_val
devuelve prvalue.
Sin embargo, ¿por qué el movimiento implícito NO se puede esperar tampoco? El uso explícito de std::move
en la declaración de devolución no parece intuitivo en este caso particular, porque generalmente no desea que RVO, que en la mayoría de los casos es una mejor optimización que mover, desaparece accidentalmente .
Probado por ambos compiladores gcc y clang con -O3
.