ja oglądając "Don’t Help the Compiler" Talk STL, gdzie ma podobny przykład na slajdzie 26:Dlaczego potrzebne jest wyraźne std :: move podczas zwracania kompatybilnego typu?
struct A
{
A() = default;
A(const A&) { std::cout << "copied" << std::endl; }
A(A&&) { std::cout << "moved" << std::endl; }
};
std::pair<A, A> get_pair()
{
std::pair<A, A> p;
return p;
}
std::tuple<A, A> get_tuple()
{
std::pair<A, A> p;
return p;
}
std::tuple<A, A> get_tuple_moved()
{
std::pair<A, A> p;
return std::move(p);
}
z tym, następujące wezwanie:
get_pair();
get_tuple();
get_tuple_moved();
Wytwarza to wyjście:
moved
moved
copied
copied
moved
moved
Wynik get_pair
jest skonstruowany w ruchu, zgodnie z oczekiwaniami. Ruch może również zostać całkowicie wyeliminowany przez NRVO, ale nie wchodzi w zakres niniejszego pytania.
Wynik z get_tuple_moved
jest również skonstruowany jako ruch, który jest jawnie określony, aby tak być. Jednak wynik get_tuple
jest skonstruowany na zasadzie kopiowania, co jest dla mnie całkowicie nieoczywiste.
Pomyślałem, że każde wyrażenie przekazane do instrukcji return
może być uważane za zawierające domyślnie move
, ponieważ kompilator wie, że i tak wyjdzie poza zakres. Wygląda na to, że się mylę. Czy ktoś może wyjaśnić, co tu się dzieje?
Zobacz również podobne, ale różnią się pytanie: When should std::move be used on a function return value?
Czy wyłączyłeś elizację kopii? Lepiej dodaj prawdziwy MCVE. – juanchopanza
@juanchopanza W rzeczywistości jest to prawdziwe MCVE, po prostu umieść metody wywołujące w 'main()'. Zachowanie dla 'get_tuple' i' get_tuple_moved' jest takie samo niezależnie od RVO, podczas gdy wpływa na 'get_pair'. – Mikhail
@Mikhail: tak właściwie to _nie jest prawdziwym MCVE (ponieważ wymaga więcej pracy niż kopiowanie i wklejanie, chociaż tylko odrobinę) :-) –