42 votes

Avec C ++ 11, est-ce un comportement indéfini d'écrire f (x ++), g (x ++)?

Je lisais cette question:

Un comportement indéfini et de la séquence des points de

et, plus précisément, le C++11 réponse, et je comprends l'idée de "séquençage" des évaluations. Mais est - il suffisant de séquençage quand j'écris:

f(x++), g(x++); ?

C'est, suis-je garanti qu' f() obtient la valeur d'origine de l' x et g() obtient une fois incrémenté x?

Notes pour nitpickers:

  • Supposons que operator++() a défini le comportement (même si nous avons bien sûr) et donc, ne f() et g(), qu'aucune exception ne sera levée, etc. - cette question n'est pas à ce sujet.
  • Supposons que operator,() n'a pas été surchargé.

49voto

StoryTeller Points 6139

Non, le comportement est défini. Pour citer le C++11 (n3337) [expr.virgule/1]:

Une paire d'expressions séparées par des virgules est évaluée de gauche à droite; la gauche expression est un jeté de la valeur de l'expression (Article [expr]). Chaque valeur de calcul et des effets secondaires associés à la gauche l'expression est séquencée avant chaque calcul de la valeur et des effets secondaires associé avec le droit d'expression.

Et je prends le mot "tous" pour dire "tous"1. L'évaluation de la deuxième x++ ne peut pas se produire avant l'appel de la séquence de f est terminé et f de rendement.2


1 Destructeur appels ne sont pas associés avec des sous-expressions, seulement avec plein d'expressions. Donc, vous allez voir ceux qui sont exécutés dans l'ordre inverse de temporaire de création de l'objet à la fin de l'expression complète.
2 Ce paragraphe ne s'applique qu'à la virgule lorsqu'il est utilisé comme un opérateur. Lorsque la virgule a une signification particulière (par exemple lors de la désignation d'un appel de fonction séquence d'argument) cela ne s'applique pas.

23voto

Joachim Pileborg Points 121221

Non, il n'est pas un comportement indéfini.

Selon cette évaluation, l'ordre et le séquençage de référence de la gauche de la virgule est entièrement évalués avant le côté droit (voir la règle 9):

9) Chaque valeur de calcul et des effets secondaires de la première (à gauche) argument de l'intégré opérateur virgule , est séquencée avant chaque calcul de la valeur et des effets secondaires de la seconde (à droite) de l'argument.

Que signifie une expression comme f(x++), g(x++) est pas indéfini.

Notez que cela n'est valable que pour l' intégré opérateur virgule.

12voto

Deduplicator Points 9096

Il dépend.

Tout d'abord, supposons que x++ lui-même, ne pas se prévaloir d'un comportement indéfini. Pensez signé débordement, incrémentation d'un passé-la-fin-pointeur, ou le suffixe-increment opérateur peut être défini par l'utilisateur).
En outre, supposons que l'invocation f() et g() avec leurs arguments et de détruire les temporaires ne pas se prévaloir d'un comportement indéfini.
Qui sont tout à fait beaucoup d'hypothèses, mais si elles sont cassées la réponse est triviale.

Maintenant, si la virgule est le haut-virgule-opérateur, la virgule dans un arc-boutée-initialisation de la liste ou de la virgule dans un mem-initialiseur de liste de, la gauche et la droite sont séquencés que ce soit avant ou après les uns des autres (et vous savez qui), afin de ne pas interférer, rendant le comportement bien défini.

struct X {
    int f, g;
    explicit X(int x) : f(x++), g(x++) {}
};
// Demonstrate that the order depends on member-order, not initializer-order:
struct Y {
    int g, f;
    explicit Y(int x) : f(x++), g(x++) {}
};
int y[] = { f(x++), g(x++) };

Si, au contraire, x++ invoque un opérateur défini par l'utilisateur-surcharge pour postfix-incrémentation, vous avez une période indéterminée le séquençage des deux instances de l' x++ , et donc un comportement non spécifié.

std::list<int> list{1,2,3,4,5,6,7};
auto x = begin(list);
using T = decltype(x);

void h(T, T);
h(f(x++), g(x++));
struct X {
    X(T, T) {}
}
X(f(x++), g(x++));

Et dans le dernier cas, vous obtenez complet à un comportement indéfini comme les deux postfix-incréments de x sont séquencé.

int x = 0;

void h(int, int);
h(f(x++), g(x++));
struct X {
    X(int, int) {}
}
X(f(x++), g(x++));

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