Sto guardando il "Don’t Help the Compiler" parlare da STL, dove ha un esempio simile sulla slitta 26:Perché lo std :: move esplicito è necessario quando si restituisce un tipo compatibile?
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);
}
Con questo, la seguente chiamata:
get_pair();
get_tuple();
get_tuple_moved();
produce questo risultato:
moved
moved
copied
copied
moved
moved
Il risultato di get_pair
viene spostato, come previsto. Una mossa può anche essere stata completamente eliminata dall'NRVO, ma non è l'argomento della presente domanda.
Il risultato di get_tuple_moved
viene anche spostato, che è esplicitamente specificato per essere tale. Tuttavia, il risultato di get_tuple
è copiato, cosa che per me non è affatto ovvia.
Ho pensato che qualsiasi espressione passata all'istruzione return
potrebbe essere considerata come implicita su move
, poiché il compilatore sa che sta per uscire comunque. Sembra che mi sbaglio. Qualcuno può chiarire, cosa sta succedendo qui?
Vedi anche legati, ma diversa domanda: When should std::move be used on a function return value?
Hai disattivato la copia elision? Inoltre, è meglio pubblicare un MCVE reale. – juanchopanza
@juanchopanza In realtà è un MCVE reale, basta mettere i metodi di chiamata in 'main()'. Il comportamento per 'get_tuple' e' get_tuple_moved' è lo stesso indipendentemente da RVO, mentre 'get_pair' è influenzato. – Mikhail
@Mikhail: così è in realtà _non_ un MCVE reale (in quanto richiede più lavoro di copia e incolla, anche se solo un piccolo pezzetto) :-) –