Il est parfaitement permis (mais pas nécessaire ) pour qu'un compilateur optimise les allocations dans votre exemple original, et encore plus dans l'exemple EDIT1 selon le §1.9 de la norme, qui est généralement appelé le règle "as-if :
Les implémentations conformes doivent émuler (uniquement) le comportement observable de la machine abstraite, comme expliqué ci-dessous :
[3 pages de conditions]
Une représentation plus lisible par l'homme est disponible à l'adresse suivante cppreference.com .
Les points pertinents sont les suivants :
- Vous n'avez pas de volatiles, donc les points 1) et 2) ne s'appliquent pas.
- Vous ne sortez/écrivez aucune donnée et n'invitez pas l'utilisateur, donc 3) et 4) ne s'appliquent pas. Mais même si c'était le cas, ils seraient clairement satisfaits dans EDIT1 (on peut dire que également dans l'exemple original, bien que d'un point de vue purement théorique, il soit illégal puisque le déroulement et la sortie du programme - théoriquement - diffèrent, mais voir deux paragraphes ci-dessous).
Une exception, même si elle n'est pas attrapée, est un comportement bien défini (pas indéfini !). Cependant, strictement parlant, dans le cas où new
(ce qui n'arrivera pas, voir aussi le paragraphe suivant), le comportement observable serait différent, à la fois par le code de sortie du programme et par toute sortie qui pourrait suivre plus tard dans le programme.
Maintenant, dans le cas particulier d'une petite allocation singulière, vous pouvez donner au compilateur l'adresse suivante "bénéfice du doute" qu'il peut garantie que l'allocation n'échouera pas.
Même sur un système soumis à une très forte pression mémoire, il n'est pas possible de démarrer un processus lorsque la granularité d'allocation disponible est inférieure à la granularité minimale. main
également. Ainsi, si cette allocation devait échouer, le programme ne pourrait jamais démarrer ou aurait déjà connu une fin peu gracieuse avant que main
est même appelé.
Dans la mesure où, en supposant que le compilateur le sache, même si l'allocation pourrait en théorie jeter il est même légal d'optimiser l'exemple original, puisque le compilateur peut pratiquement garantir que cela ne se produira pas.
<sérieusement indécis>
D'autre part, il est pas Il est possible (et comme vous pouvez le constater, c'est un bug du compilateur) d'optimiser l'allocation dans votre exemple EDIT2. La valeur est consommée pour produire un effet observable de l'extérieur (le code de retour).
Notez que si vous remplacez new (std::nothrow) int[1000]
avec new (std::nothrow) int[1024*1024*1024*1024ll]
(c'est une allocation de 4 To !), ce qui est -- sur les ordinateurs actuels -- garanti d'échouer, il optimise quand même l'appel. En d'autres termes, il renvoie 1 alors que vous avez écrit un code qui doit renvoyer 0.
@Yakk a soulevé un bon argument contre cela : Tant que la mémoire n'est jamais touchée, un pointeur peut être renvoyé, et aucune RAM réelle n'est nécessaire. En ce sens, il serait même légitime d'optimiser l'allocation dans EDIT2. Je ne suis pas sûr de savoir qui a raison et qui a tort ici.
Une allocation de 4 To est pratiquement garantie d'échouer sur une machine qui ne dispose pas d'une quantité de RAM d'au moins deux gigaoctets, simplement parce que le système d'exploitation doit créer des tables de pages. Bien sûr, la norme C++ ne se soucie pas des tables de pages ou de ce que le système d'exploitation fait pour fournir de la mémoire, c'est vrai.
Mais d'un autre côté, l'hypothèse "ça va marcher si on ne touche pas à la mémoire" s'appuie sur sur un tel détail et sur quelque chose que l'OS fournit. L'hypothèse selon laquelle si la RAM n'est pas touchée, c'est qu'elle n'est pas nécessaire, n'est vraie que dans les cas suivants parce que le système d'exploitation fournit de la mémoire virtuelle. Et cela implique que le système d'exploitation doit créer des tables de pages (je peux prétendre que je ne suis pas au courant, mais cela ne change rien au fait que je m'y fie quand même).
Par conséquent, je pense qu'il n'est pas correct à 100% de supposer d'abord l'un et de dire ensuite "mais nous ne nous soucions pas de l'autre".
Donc, oui, le compilateur peut supposer qu'une allocation de 4TiB est en général parfaitement possible tant que la mémoire n'est pas touchée, et qu'elle peut supposer qu'il est généralement possible de réussir. Il pourrait même supposer qu'il est probable de réussir (même si ce n'est pas le cas). Mais je pense que dans tous les cas, on n'est jamais autorisé à supposer que quelque chose doit travailler quand il y a une possibilité d'échec. Et non seulement il y a une possibilité d'échec, mais dans cet exemple, l'échec est même l'élément le plus important. plus probable possibilité.
</i> Légèrement indécis>