Pourquoi ne std::move empêcher RVO?

Dans de nombreux cas de retour d'un local à partir d'une fonction, RVO coups de pied dans. Cependant, je pensais que l'utilisation explicite std::move permettrait au moins de faire respecter le déplacement lors de la RVO ne se fait pas, mais que RVO est toujours en vigueur, lorsque cela est possible. Cependant, il semble que ce n'est pas le cas.

#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;
}

J'ai testé ce code avec VC++11 et GCC 4.71, debug et release (-O2) config. La copie ctor n'est jamais appelée. Le mouvement ctor est appelé par VC++11 dans le debug config. En fait, tout semble aller pour le mieux avec ces compilateurs en particulier, mais à ma connaissance, RVO est facultatif.

Cependant, si je utiliser explicitement move:

HeavyWeight MakeHeavy()
{
    HeavyWeight heavy;
    return std::move(heavy);
}

le déplacer ctor est toujours appelée. Donc, en essayant de la rendre "sûr", il est pire.

Mes questions sont les suivantes:

- Pourquoi ne std::move empêcher RVO?

- Quand est-il préférable de "l'espoir pour le meilleur", et s'appuient sur RVO, et quand dois-je utiliser explicitement std::move? Ou, en d'autres termes, comment puis-je laisser le compilateur d'optimisation de faire son travail et toujours appliquer déplacer si RVO n'est pas appliquée?

  • Pourquoi toujours parler de "l'espoir pour le meilleur" ces jours-ci? Quel type de compilateur utilisent-ils qui a le C++11, mais ne peut pas RVO correctement?
  • Copie élision (le mécanisme derrière la RVO) est autorisée que dans certaines, des conditions strictes. Écrit std::move empêche que ces conditions soient remplies.
  • Et ces conditions empêché par std::move sont...?
  • std::move empêche NRVO (nommé RVO). RVO en général n'est pas affecté (autant que je sache)
  • Pouvez-vous indiquer une référence décrivant le raisonnement derrière empêcher cela? Ne déplacez élision jamais arriver?
  • Nope, retour std::move(poids Lourd()); appelle encore les déplacer ctor.
  • Déplacer élision ne se produise, mais pas quand explicitement en utilisant std::move. De drôles de trucs.
  • J'ai pensé que j'étais juste d'être approfondie en faisant explicite std::move est, au contraire il me semble que j'ai été le sabotage moi-même! 😉
  • Je n'ai pas dit que le compilateur ne RVO dans le std::move cas. J'ai seulement dit, qu'ils ne peuvent pas faire NRVO, mais (comme je l'ai dit, autant que je sache) peut encore faire RVO. Il est dépendant de l'implémentation.
  • Vous n'êtes pas seul.
  • Le déménagement peut toujours être ramené si le compilateur peut prouver qu'il ne change pas le programme du comportement.
  • Le problème des cas est celui où le changement de comportement est admise, à savoir l'omission de copier/déplacer constructeur appelle. Depuis le cas de test, par définition, doit contenir les effets secondaires, vous êtes limité à des optimisations qui s'appuient sur une copie élision et les règles du jeu.