En C, le résultat de la pré-et post-incrémentation sont rvalues et nous ne pouvons pas attribuer à une rvalue, nous avons besoin d'une lvalue(voir aussi: la Compréhension des lvalues et rvalues en C et C++) . On peut voir en allant sur le projet de norme C11 section 6.5.2.4
Postfix d'incrémentation et de décrémentation les opérateurs qui le dit (c'est moi qui souligne à l'avenir):
Le résultat de la postfix ++ opérateur est la valeur de la
l'opérande. [...] Voir la discussion de l'additif opérateurs et composé
cession pour plus d'informations sur les contraintes, les types, et les conversions et
les effets des opérations sur les pointeurs. [...]
Donc le résultat de la post-incrémentation est une valeur qui est synonyme pour rvalue et nous pouvons confirmer cela en allant à la section 6.5.16
des opérateurs d'Affectation dont le paragraphe ci-dessus nous montre à approfondir la compréhension des contraintes et des résultats, il dit:
[...] Une expression d'affectation a la valeur de l'opérande gauche après le
d'affectation, mais n'est pas une lvalue.[...]
ce qui confirme le résultat de la post-incrémentation n'est pas une lvalue.
Pour la pré-incrémentation, nous pouvons voir à partir de la section 6.5.3.1
Préfixe d'incrémentation et de décrémentation les opérateurs qui dit:
[...]Voir la discussion de l'additif opérateurs et composé d'affectation pour
informations sur les contraintes, les types, les effets secondaires, et les conversions et
les effets des opérations sur les pointeurs.
également des points de 6.5.16
comme la post-incrémentation ne et, par conséquent, le résultat de la pré-incrémentation dans C est pas une lvalue.
En C++ post-incrémentation est aussi une rvalue, plus précisément un prvalue nous pouvons confirmer cela en allant à la section 5.2.6
d'Incrémentation et de décrémentation qui dit:
[...]Le résultat est un prvalue. Le type du résultat est la cv-sans réserve
version du type de l'opérande[...]
À l'égard de la pré-incrémentation de C et de C++ diffèrent. En C, le résultat est une rvalue alors qu'en C++ le résultat est une lvalue ce qui explique pourquoi ++ptr = ptr1;
fonctionne en C++ mais pas en C.
Pour le C++ c'est couvert dans la section 5.3.2
d'Incrémentation et de décrémentation qui dit:
[...]Le résultat est la mise à jour de l'opérande; c'est une lvalue, et c'est un
peu-champ si l'opérande est un peu de champ.[...]
Pour comprendre si:
++ptr = ptr1;
est bien définie ou non en C++, nous avons besoin de deux approches différentes pour la C++11) et un pour le C++11.
Avant C++11 cette expression appelle un comportement indéfini, puisque c'est la modification de l'objet plus d'une fois au sein de la même séquence de point. Nous pouvons voir cela à un Pré C++11 projet de norme section 5
Expressions qui dit:
Sauf indication contraire, l'ordre d'évaluation des opérandes de l'individu
les opérateurs et les sous-expressions des expressions individuelles, et de l'ordre
dans les effets secondaires qui prendre place, est indéterminé.57) Entre le
précédent et suivant de la séquence de point un scalaire objet est stocké
valeur modifiée au plus une fois par l'évaluation d'une expression.
En outre, l'état de la valeur doit être consulté pour déterminer le
valeur à stocker. Les exigences de ce paragraphe sont remplies
pour chaque admissibles de la commande de la sous-expressions d'un plein
l'expression, sinon le comportement est indéfini. [ Exemple:
i = v[i ++]; / / the behavior is undefined
i = 7 , i++ , i ++; / / i becomes 9
i = ++ i + 1; / / the behavior is undefined
i = i + 1; / / the value of i is incremented
fin de l'exemple ]
Nous sommes incrémentation ptr
, puis par la suite en lui attribuant, qui est d'apporter deux modifications et dans ce cas, la séquence se produit à la fin de l'expression après l' ;
.
Pour C+11, nous devrions aller de rapport de défaut 637: des règles d'ordonnancement et de l'exemple de désaccord qui a été le rapport de défaut qui a abouti à:
i = ++i + 1;
devient de plus en plus, les comportements définis en C++11, alors qu'avant C++11 c'était un comportement indéfini. L'explication dans ce rapport est l'un des meilleurs que j'ai vu et le lire à plusieurs reprises était instructif et m'a aidé à comprendre beaucoup de concepts dans une nouvelle lumière.
La logique qui conduisent à cette expression devient ainsi défini comportement va comme suit:
L'affectation d'effets secondaires est nécessaire pour être séquencés après la valeur des calculs à la fois de ses LHS et RHS (5.17 [expr.cul] l'alinéa 1).
Le LHS (i) est une lvalue, donc sa valeur de calcul consiste à calculer l'adresse de je.
Pour la valeur de calcul de la RHS (++i + 1), il est nécessaire d'abord de la valeur de calcul de la lvalue expression ++je puis faire une lvalue-à-rvalue de conversion sur le résultat. Cela garantit que l'incrémentation d'effets secondaires est séquencée avant le calcul de l'opération d'addition, qui à son tour est séquencée avant l'assignation des effets secondaires. En d'autres termes, il donne un ordre précis et la valeur finale de cette expression.
La logique est quelque peu similaire pour:
++ptr = ptr1;
La valeur des calculs de la LHS et RHS sont séquencée avant l'assignation des effets secondaires.
Le membre de droite est une lvalue, donc sa valeur de calcul consiste à calculer l'adresse de ptr1.
Pour la valeur de calcul de la LHS (ptr++), il est nécessaire d'abord de la valeur de calcul de la lvalue expression ptr ++et ensuite faire une lvalue-à-rvalue de conversion sur le résultat. Cela garantit que l'incrémentation d'effets secondaires est séquencée avant l'assignation des effets secondaires. En d'autres termes, il donne un ordre précis et la valeur finale de cette expression.
Note
L'OP a dit:
Oui, je comprends, c'est salissant et vous avez à traiter avec des non alloué
de mémoire, mais il fonctionne et compile.
Les pointeurs de tableau non les objets sont considérés comme des tableaux de taille un additif pour les opérateurs, je vais me permettre de citer le projet de norme C++ mais C11 a presque exactement le même texte. À partir de la section 5.7
Additif opérateurs:
Pour l'application de ces opérateurs, un pointeur vers un objet nonarray
se comporte comme un pointeur vers le premier élément d'un tableau de
de longueur avec le type de l'objet comme type d'élément.
et plus nous dit pointant vers un passé la fin d'un tableau est valide aussi longtemps que vous n'avez pas déréférencer le pointeur:
[...]Si le pointeur de l'opérande et le résultat pointez sur les éléments de
le même objet de tableau, ou un au-delà du dernier élément du tableau
l'objet, l'évaluation ne doit pas produire un dépassement de capacité; sinon, l'
le comportement est indéfini.
donc:
++ptr ;
est toujours un pointeur valide.