Question

Cette question est dans un aspect différent (également limité au CCG). Ma question est destinée uniquement à objets sans nom. Optimisation de la valeur de retour est autorisé à changer le comportement observable du programme résultant. Cela semble également être mentionné en standard.

Cependant, ceci "autorisé à" Le terme est déroutant. Cela signifie-t-il que RVO est garanti se produire sur chaque compilateur. En raison du RVO en dessous des modifications de code, son comportement observable:

#include<iostream>
int global = 0;
struct A {
  A(int *p) {}
  A(const A &obj) { ++ global; }
};

A foo () {  return A(0); }  // <--- RVO happens
int main () {
  A obj = foo(); 
  std::cout<<"global = "<<global<<"\n"; // prints 0 instead of 2
}

Ce programme est-il supposé imprimer global = 0 Pour toutes les implémentations, indépendamment des optimisations du compilateur et de la taille de la méthode de foo ?

Était-ce utile?

La solution

Selon la norme, le programme peut imprimer 0, 1 ou 2. Le paragraphe spécifique en C ++ 11 est 12.8p31 qui commence par:

Lorsque certains critères sont remplis, une implémentation est autorisée à omettre la construction de copie / déplacer un objet de classe, même si le constructeur de copie / déplacer et / ou le destructeur de l'objet a des effets secondaires.

Notez que les deux élimination en copie ne sont pas une optimisation qui tombe dans le comme si Règle (qui exige que le comportement du programme soit cohérent avec le comportement du même programme comme si Aucune optimisation n'avait eu lieu). La norme permet explicitement à l'implémentation de générer différents comportements observables, et c'est à vous le programmeur de demander à votre programme de ne pas dépendre de cela (ou d'accepter les trois résultats possibles).

Remarque 2: 1 n'est mentionné dans aucune des réponses, mais c'est un résultat possible. Il y a deux copies potentielles qui se déroulent, de la variable locale de la fonction à l'objet retourné à l'objet en main, le compilateur ne peut en éluder aucun, un ou les deux copies générant les trois sorties possibles.

Autres conseils

Il ne peut pas être garanti. Si vous essayiez d'écrire une telle garantie de manière cohérente, vous trouverez impossible de le faire.

Par exemple, considérez ce code:

std::string f() {
  std::string first("first");
  std::string second("second");
  return FunctionThatIsAlwaysFalse() ? first : second;
}

La fonction FunctionThatIsAlwaysFalse revient toujours false, mais vous ne pouvez le dire que si vous faites des optimisations inter-modules. La norme devrait-elle exiger que chaque compilateur ait une optimisation inter-module afin qu'il puisse utiliser RVO dans ce cas? Comment cela fonctionnerait-il? Ou devrait-il interdire à un compilateur d'utiliser RVO lorsque des optimisations inter-modules sont nécessaires? Comment cela fonctionnerait-il? Comment peut-il arrêter les compilateurs assez intelligents pour voir que RVO est possible de le faire et ceux qui ne sont pas de ne pas le faire?

La liste standard devrait-elle la liste standard que tous les compilateurs d'optimisation sont tenus de prendre en charge avec RVO? Et devrait-il interdire RVO dans d'autres cas? Cela ne viendrait-il pas le point d'optimiser les compilateurs?

Et qu'en est-il des cas où le compilateur pense que RVO réduira les performances? Le compilateur doit-il être tenu de faire une optimisation qu'il pense être mauvais? Par exemple:

if(FunctionCompilerKnowsHasNoSideEffectsAndThinksMostlyReturnsFalse())
  return F(3); // Here RVO is a pessimization
else
{
 Foo j=F(3);
 return Foo(j);
}

Ici, si le compilateur n'est pas tenu de faire RTO, si peut éviter le if et l'appel de fonction, car sans RTO, le code est le même dans les deux moitiés. Devriez-vous forcer le compilateur à faire une optimisation qu'il pense aggraver les choses? Pourquoi?

Il n'y a vraiment aucun moyen de faire fonctionner une telle garantie.

Parlant pédantiquement sa mise en œuvre définie. Les compilateurs modernes sont suffisamment intelligents pour faire ce type d'optimisation.

Mais rien ne garantit que le comportement serait exactement le même à travers les implémentations. C'est ce que implémentation définie Le comportement est tout au sujet.

"Autorisé à" dans ce contexte signifie que 0 ou 1 ou 2 sont des sorties conformes standard.

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