Question

J'aimerais m'assurer que mes routines tirent parti du (N)RVO autant que possible.À part analyser le démontage résultant, y a-t-il quelque chose que je puisse faire ou vérifier si une routine est en cours de compilation avec (N)RVO ?À ce stade, je m'intéresse principalement à MSVC et GCC.

Était-ce utile?

La solution

Non, pas vraiment.

Cependant, vous pouvez suivre les directives lors de l'écriture de votre code.


Optimisation de la valeur de retour sans nom

Ceci est pratiquement déclenché à chaque fois que vous renvoyez un temporaire, même en mode débogage.

return MyObject(....);

Optimisation de la valeur de retour nommée

Ceci est quasiment déclenché à chaque fois que la fonction renvoie toujours le même objet temporaire :

MyObject func() {
  MyObject result;
  if (...) { return result; }

  result.push(0);
  return result;
}

Vous pouvez les mélanger, mais il devient quasiment impossible pour le compilateur d'appliquer RVO dans ce cas :

MyObject func() {
  MyObject result;
  if (...) { return MyObject(...); }

  return result;
}

Ici, il est probable qu’un retour bénéficiera du RVO et l’autre non.Et je parierais sur l'optimisation du premier car vous seriez bloqué si vous créiez de manière spéculative result dans la fente de retour et je dois soudainement prendre le if bifurquer.Notez que la simple réorganisation des instructions fonctionne :

MyObject func() {
  if (...) { return MyObject(...); }

  MyObject result;

  return result;
}

La règle générale pour le NRVO est donc qu'il ne devrait y avoir aucun return déclaration entre la déclaration de result et le return result; instruction qui renvoie autre chose que result lui-même.


Si vous suivez cela, vous mettez toutes les chances de votre côté.Et puis c'est juste une question de révision du code.

Et vous rendez également votre code plus facile à lire puisque vous ne déclarez pas de variables avant de savoir que vous en avez vraiment besoin !

Autres conseils

Vous pouvez ajouter des méthodes de débogage au destructeur:

struct A
{
   ~A() { cout << "destructor called"; }
};

A foo()
{
   A a;
   return a;
}

Si le destructeur est appelé, le RVO n'était probablement pas appliqué.

Les moyens possibles auxquels je peux penser sont :

  1. Implémenter un mécanisme de comptage de références au sein de votre classe qui garde une trace du nombre d'instances créées via la classe, quelque chose comme un shared_ptr le fait, de cette façon, vous pouvez détecter des copies supplémentaires de votre classe en cours de création et de suppression si l'élision de copie ne se produit pas.

  2. Vous pouvez simplement mettre des traces de débogage dans le constructeur de copie et le destructeur de votre classe, si l'élision de copie ne se produit pas, vous verrez beaucoup de traces de débogage successives du constructeur de copie et du destructeur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top