27 votes

Est-ce un comportement indéterminé si plusieurs opérandes dans une expression composée de modifier le même objet?

Je me souviens vaguement avoir lu quelque part que c'est un comportement indéterminé si plusieurs opérandes dans une expression composée de modifier le même objet.

Je pense qu'un exemple de cette UB est indiqué dans le code ci-dessous mais je n'ai compilé sur g++, clang++ et visual studio et tous imprimer les mêmes valeurs et ne suffisent pas à produire des valeurs imprévisibles dans différents compilateurs.

#include <iostream>

int a( int& lhs ) { lhs -= 4; return lhs; }
int b( int& lhs ) { lhs *= 7; return lhs; }
int c( int& lhs ) { lhs += 1; return lhs; }
int d( int& lhs ) { lhs += 2; return lhs; }
int e( int& lhs ) { lhs *= 3; return lhs; }

int main( int argc, char **argv )
{
    int i = 100;
    int j = ( b( i ) + c( i ) ) * e( i ) / a( i ) * d( i );

    std::cout << i << ", " << j << std::endl;

    return 0;
}

Ce comportement est-il pas défini ou j'ai en quelque sorte entraîné une description de soi-disant UB qui n'est pas réellement indéfinie?

Je vous serais reconnaissant si quelqu'un pouvait poster un exemple de cette UB et peut-être même m'indiquer où dans la norme C++ qu'il dit qu'il est UB.

34voto

AndreyT Points 139512

Pas de. Il n'est pas. Un comportement indéfini est hors de question ici (en supposant que l' int de l'arithmétique ne déborde pas): toutes les modifications apportées i sont isolés par une séquence de points (à l'aide de C++03 terminologie). Il y a une séquence de point à l'entrée de chaque fonction et il y a un point de séquence à la sortie.

Le comportement est non spécifié ici.

Votre code suit le même schéma que l'exemple classique souvent utilisé pour illustrer la différence entre l' indéfini et indéterminé de comportement. Considérez ceci

int i = 1;
int j = ++i * ++i;

Les gens vont souvent que dans cet exemple, le résultat ne dépend pas de l'ordre de l'évaluation et, par conséquent, j doit toujours être de 6". C'est une défaillance de demande, puisque le comportement est indéfini.

Toutefois, dans cet exemple

int inc(int &i) { return ++i; }

int i = 1;
int j = inc(i) * inc(i);

le comportement est officiellement seulement indéterminée. À savoir, l'ordre d'évaluation n'est pas spécifié. Cependant, depuis le résultat de l'expression ne dépend pas de l'ordre de l'évaluation à tous, en j est garanti pour toujours finir en 6. Ceci est un exemple de la façon dont généralement dangereux comportement quelconque combinaison peut conduire à la perfection résultat défini.

Dans votre cas, le résultat de votre expression ne dépendent de façon critique de l'ordre de l'évaluation, ce qui signifie que le résultat sera imprévisible. Pourtant, il n'y a pas un comportement non défini ici, c'est à dire le programme n'est pas autorisé à formater votre disque dur. Il est uniquement permis de produire le résultat imprévisible en j.

P. S. Encore, il pourrait s'avérer que certains des scénarios d'évaluation pour votre expression de plomb signé débordement d'entier (je n'ai pas analysé tous), qui, par elle-même déclenche un comportement indéfini. Donc, il y a encore du potentiel pour un quelconque comportement conduisant à un comportement indéfini dans votre expression. Mais ce n'est probablement pas ce que votre question est à propos.

12voto

Loki Astari Points 116129

Pas de son pas un comportement indéfini.

Mais il ne invoquer un comportement non spécifié.

C'est parce que l'ordre des sous-expressions sont évaluées n'est pas spécifié.

int j = ( b( i ) + c( i ) ) * e( i ) / a( i ) * d( i );

Dans l'expression ci-dessus les sous-expressions:

b(i)
c(i)
e(i)
a(i)
d(i)

Peut être évalué dans n'importe quel ordre. Parce qu'ils ont tous des effets secondaires, les résultats dépendent de la présente ordonnance.

Si vous divisez l'expression dans toutes les sous-expressions (c'est un pseudo-code)
Ensuite, vous pouvez voir toute commande requis. Non seulement les expressions ci-dessus être fait dans n'importe quel ordre, potentiellement, ils peuvent être entrelacées avec le niveau plus élevé des sous-expressions (avec seulement quelques constraits).

tmp_1 = b(i)           // A
tmp_2 = c(i)           // B
tmp_3 = e(i)           // C
tmp_4 = a(i)           // D
tmp_5 = d(i)           // E

tmp_6 = tmp_1 + tmp_2  // F   (Happens after A and B)
tmp_7 = tmp_6 * tmp_3  // G   (Happens after C and F)
tmp_8 = tmp_7 / tmp_4  // H   (Happens after D and G)
tmp_9 = tmp_8 * tmp_5  // I   (Happens after E and H)

int j = tmp_9;         // J   (Happens after I)

8voto

Dietmar Kühl Points 70604

Ce n'est pas un comportement indéfini, mais il a indéterminée résultats: Le seul objet modifié est - i via les références transmises aux fonctions. Toutefois, l'appel aux fonctions d'introduire la séquence de points (je n'ai pas le C++ 2011 avec moi: ils sont appelés quelque chose de différent là), c'est à dire il n'y a pas de problème de multiples changements au sein d'une expression provoquant un comportement indéfini.

Cependant, l'ordre dans lequel l'expression est évaluée n'est pas spécifiée. Comme un résultat, vous pouvez obtenir des résultats différents si l'ordre de l'évaluation des changements. Ce n'est pas un comportement indéfini: Le résultat est l'un de tous les ordres possibles de l'évaluation. Un comportement indéfini signifie que le programme peut se comporter d'une manière qu'il veut, y compris la production de la "attendus" (prévue par le programmeur) résultats pour l'expression en question, tout en currupting toutes les autres données.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X