2009-06-15 4 views
4

Considérons le code suivant:C opérateur de décalage de priorité de bizarrerie

typedef vector<int> intVec; 

intVec& operator<<(intVec& dst, const int i) { 
    dst.push_back(i); 
    return dst; 
} 
int intResult0() { 
    return 23; 
} 
int intResult1() { 
    return 42; 
} 

// main 
intVec v; 
v << intResult0() << intResult1(); 

La chose étrange est que le compilateur génère un code, qui évalue intResult1AVANTintResult0 (testé avec les plus récentes gcc und VC). Pourquoi le compilateur ferait-il cela? En faisant cela, le temps entre l'évaluation et l'utilisation des valeurs respectives est (inutilement) augmenté (?), C'est-à-dire que l'on extrait en premier le 42, mais que l'on pousse le dernier au vecteur. Est-ce que le standard C++ le dicte?

+0

heh, je viens couru dans cette dernière nuit avec l'opérateur + = T La chose confuse pour moi est qu'en lisant le code, on s'attendrait à ce que intResult1 soit appelé second parce qu'il utilise la valeur retournée par intResult0 pour son premier argument. – Dolphin

Répondre

12

Conformément à l'article Stroustrup 6.2.2:

L'ordre d'évaluation des sous-expressions dans une expression est indéfini.

10

Ceci n'a rien à voir avec la précédence.

Il n'y a pas de point de séquence dans cette dernière instruction, donc le compilateur est libre d'évaluer les sous-expressions dans l'ordre qu'il veut, tant que la précédence est utilisée lors de la combinaison des sous-expressions.

Notez que l'ordre de priorité et non définit un ordre d'évaluation global - il définit simplement comment les opérandes d'une expression avec plusieurs opérateurs seront combinés.

Par exemple, dans l'expression suivante:

a() * b() + c() 

à un moment donné, le compilateur aurait besoin d'évaluer (a() * b()) avant d'ajouter dans le résultat de c(), mais il n'y a rien qui dit ce qui commande tous les besoins d'appels de fonction individuels être fabriqué. Le compilateur peut tout à fait facilement décider d'appeler c() en premier, pousser le résultat sur une pile, puis faire ce qu'il faut pour évaluer l'expression (a() * b()) (dans ce cas, il peut décider d'évaluer b() en premier).

Le seul rôle que joue la priorité est que le compilateur n'est pas permis d'évaluer l'expression:

a() * (b() + c()) 
14

L'ordre d'évaluation des sous-expressions entre deux points de séquence est définie.

Le code ci-dessus est le sucre syntaxique pour:

v.operator<<(intResult0()).operator<<(intResult1()); 

La seule contrainte que le compilateur a, est qu'il doit évaluer tous les paramètres avant qu'une méthode est appelée et obéir aux règles de priorité. Mais tant qu'il suit ces règles, chaque implémentation est autorisée à choisir les détails et en tant que tel cet ordre peut changer entre les compilateurs.

Dans cet exemple:

  • Il est parfaitement légal d'appeler intResult1() avant intResult2().
  • Mais intResult0() doit être appelée avant l'appel à l'opérateur < <() (à gauche)
  • et intResult1() doit être appelée avant l'appel à l'opérateur < <() (à droite)
  • et opérateur < <() (à gauche) doit être appelé avant opérateur < <() (à droite)

Voir ici pour plus d'informations:
What are all the common undefined behaviours that a C++ programmer should know about?

et

What are all the common undefined behaviours that a C++ programmer should know about?

2

The Standard C++, 5: 4

Sauf indication contraire, l'ordre de évaluation des opérandes individuels les opérateurs et les sous-expressions de expressions individuelles, et l'ordre dans laquelle les effets secondaires prennent lieu, est non précisée