Mis à jour, voir ci-dessous!
J'ai entendu et lu que C ++ 0x permet à un compilateur d'imprimer "Hello" pour l'extrait suivant
#include <iostream>
int main() {
while(1)
;
std::cout << "Hello" << std::endl;
}
Cela a apparemment quelque chose à voir avec les threads et les capacités d'optimisation. Il me semble que cela peut surprendre beaucoup de gens.
Quelqu'un a-t-il une bonne explication de la raison pour laquelle cela était nécessaire pour permettre? Pour référence, le projet le plus récent de C ++ 0x indique à6.5/5
Une boucle qui, en dehors de l'instruction for-init dans le cas d'une instruction for,
- ne fait aucun appel aux fonctions d'E / S de la bibliothèque, et
- n'accède ni ne modifie les objets volatils, et
- n'effectue aucune opération de synchronisation (1.10) ou opération atomique (Article 29)
peut être supposé par la mise en œuvre se terminer. [Remarque: Ceci est destiné à permettre les transformations du compilateur, telles que la suppression de boucles vides, même lorsque la terminaison ne peut pas être prouvée. - note de fin]
Éditer:
Cet article perspicace parle de ce texte de normes
Malheureusement, les mots «comportement indéfini» ne sont pas utilisés. Cependant, chaque fois que le standard dit "le compilateur peut supposer P", il est sous-entendu qu'un programme qui a la propriété not-P a une sémantique non définie.
Est-ce correct et le compilateur est-il autorisé à imprimer "Bye" pour le programme ci-dessus?
Il y a un fil encore plus perspicace ici , qui concerne un changement analogue à C, commencé par le gars qui a fait l'article lié ci-dessus. Entre autres faits utiles, ils présentent une solution qui semble s'appliquer également à C ++ 0x ( mise à jour : cela ne fonctionnera plus avec n3225 - voir ci-dessous!)
endless:
goto endless;
Un compilateur n'est pas autorisé à optimiser cela, semble-t-il, car ce n'est pas une boucle, mais un saut. Un autre gars résume le changement proposé dans C ++ 0x et C201X
En écrivant une boucle, le programmeur affirme soit que la boucle fait quelque chose avec un comportement visible (effectue des E / S, accède à des objets volatils, ou effectue une synchronisation ou des opérations atomiques), soit qu'elle finit par se terminer. Si je viole cette hypothèse en écrivant une boucle infinie sans effets secondaires, je mens au compilateur et le comportement de mon programme n'est pas défini. (Si j'ai de la chance, le compilateur peut m'en avertir.) Le langage ne fournit pas (ne fournit plus?) Un moyen d'exprimer une boucle infinie sans comportement visible.
Mise à jour du 3.1.2011 avec n3225: le Comité a déplacé le texte au 1.10 / 24 et dit
L'implémentation peut supposer que n'importe quel thread effectuera éventuellement l'une des opérations suivantes:
- mettre fin,
- appeler une fonction d'E / S de bibliothèque,
- accéder ou modifier un objet volatil, ou
- effectuer une opération de synchronisation ou une opération atomique.
L' goto
astuce ne fonctionnera plus!
int x = 1; for(int i = 0; i < 10; ++i) do_something(&i); x++;
en for(int i = 0; i < 10; ++i) do_something(&i); int x = 2;
? Ou peut-être l'inverse, en x
étant initialisé 2
avant la boucle. Il peut dire do_something
ne se soucie pas de la valeur de x
, donc c'est une optimisation parfaitement sûre, si do_something
cela ne fait pas i
changer la valeur de de telle sorte que vous vous retrouvez dans une boucle infinie.
main() { start_daemon_thread(); while(1) { sleep(1000); } }
pourrait simplement se terminer immédiatement au lieu d'exécuter mon démon dans un thread d'arrière-plan?
while(1) { MyMysteriousFunction(); }
doit être compilable indépendamment sans connaître la définition de cette fonction mystérieuse, non? Alors, comment pouvons-nous déterminer s'il appelle des fonctions d'E / S de bibliothèque? En d'autres termes: cette première puce qui pourrait être formulée ne fait certainement aucun appel aux fonctions .