In molti casi quando si restituisce un locale da una funzione, RVO entra in gioco. Tuttavia, ho pensato che usare esplicitamente lo std::move
avrebbe dovuto forzare lo spostamento quando RVO non si verificava, ma quel RVO è ancora applicato quando possibile. Tuttavia, sembra che questo non sia il caso.Perché std :: move impedisce RVO?
#include "iostream"
class HeavyWeight
{
public:
HeavyWeight()
{
std::cout << "ctor" << std::endl;
}
HeavyWeight(const HeavyWeight& other)
{
std::cout << "copy" << std::endl;
}
HeavyWeight(HeavyWeight&& other)
{
std::cout << "move" << std::endl;
}
};
HeavyWeight MakeHeavy()
{
HeavyWeight heavy;
return heavy;
}
int main()
{
auto heavy = MakeHeavy();
return 0;
}
Ho provato questo codice con VC++ 11 e GCC 4.71, debug e di rilascio (-O2
) config. Il copy ctor non viene mai chiamato. Il codice di spostamento viene chiamato solo da VC++ 11 in debug config. In realtà, sembra che tutto vada bene con questi compilatori in particolare, ma per quanto ne so, RVO è facoltativo.
Tuttavia, se uso esplicitamente move
:
HeavyWeight MakeHeavy()
{
HeavyWeight heavy;
return std::move(heavy);
}
ctor Move è sempre chiamato. Quindi, cercare di renderlo "sicuro" lo rende peggiore.
Le mie domande sono:
- Perché std::move
impedisce RVO?
- Quando è meglio "sperare per il meglio" e affidarsi a RVO e quando è necessario utilizzare esplicitamente lo std::move
? O, in altre parole, come posso lasciare che l'ottimizzazione del compilatore faccia il suo lavoro e continui a imporre il movimento se RVO non viene applicato?
Perché la gente parla ancora di "speranza per il meglio" in questi giorni? Che tipo di compilatore sta usando che ha il supporto per C++ 11 ma non può RVO correttamente? –
Copia elisione (il meccanismo dietro RVO) è consentita solo in determinate condizioni rigorose. Scrivere 'std :: move' impedisce che tali condizioni vengano soddisfatte. –
@KerrekSB E queste condizioni prevenute da std :: move are ...? – cdoubleplusgood