web-dev-qa-db-fra.com

Les adresses des membres de données se situent-elles entre (this) et (this + 1)?

Supposons que nous ayons les deux inégalités suivantes dans une fonction membre

this <=  (void *) &this->data_member

et

&this->data_member < (void *) (this+1) 

Sont-ils garantis pour être vrai? (Ils semblent être vrais dans quelques cas que j'ai vérifiés.)

Edit: J'ai raté les esperluettes, maintenant c'est la forme correcte des inégalités. 

7
user10636819

D'après le projet de norme 4713 du CPP: 

6.6.2 Modèle d'objet [intro.object]/7
Un objet de type trivialement copiable ou de format standard (6.7) doit occuper des octets de stockage contigus. 

12.2 Membres de classe [class.mem]/18
Les membres de données non statiques d'une classe (non syndiquée) avec le même contrôle d'accès (clause 14) sont alloués de sorte que les membres ultérieurs aient des adresses plus élevées dans un objet de classe. 

12.2 Membres de classe [class.mem]/25
Si un objet de classe de mise en page standard a des membres de données non statiques, son adresse est la même que l'adresse de son premier membre de données non statique. Sinon, son adresse est la même que l'adresse de son premier sous-objet de classe de base (le cas échéant). 

En prenant tout ce qui précède ensemble, nous pouvons dire que la première équation est valable pour au moins les objets copiables de manière triviale.

Également à partir de la référence en ligne cpp :

Le résultat de la comparaison de deux pointeurs vers des objets (après conversions) est défini comme suit:

1) Si deux pointeurs pointent sur des éléments différents du même tableau ou sur des sous-objets dans des éléments différents du même tableau, le pointeur sur l'élément dont l'indice est le plus élevé compare plus haut. En d'autres termes, le résultat de la comparaison des pointeurs est identique à celui de la comparaison des index des éléments sur lesquels ils pointent.
2) Si un pointeur pointe sur un élément d'un tableau ou sur un sous-objet de l'élément du tableau et qu'un autre pointeur pointe un peu après le dernier élément du tableau, ce dernier se compare davantage. Les pointeurs sur des objets uniques sont traités comme des pointeurs sur des tableaux de un: &obj+1 compare plus que &obj (depuis C++ 17)

Ainsi, si votre data_member est pas un pointeur et que la mémoire ne lui a pas été allouée séparément, les équations que vous avez publiées restent valables

5
P.W

Le texte standard } complet correspond à ceci:

[expr.rel] - 4: Résultat de la comparaison de pointeurs inégaux avec des objets82 est défini en termes d'un partial order conforme aux règles suivantes:

Nous avons affaire ici à une commande partielle et non totale. Cela signifie que a < b et b < c implique a < c, mais pas grand chose d’autre.

(La note 82 indique que les objets non-tableaux sont considérés comme des éléments d'un tableau à élément unique à cette fin, avec la signification/le comportement intuitif de "pointeur sur un élément au-delà de la fin").

(4.1) Si deux pointeurs pointent sur des éléments différents de le même tableau, ou sur leurs sous-objets, le pointeur sur l'élément dont l'indice est le plus élevé est nécessaire pour comparer plus grand. 

Les pointeurs vers des membres différents ne sont pas des pointeurs vers (sous-objets de) des éléments du même tableau. Cette règle ne s'applique pas.

(4.2) Si deux pointeurs pointent vers des membres de données non statiques différents de le même objet, ou vers des sous-objets de ces membres, de manière récursive, le pointeur sur le membre déclaré plus tard est requis pour une comparaison plus importante, à condition que les deux membres aient le même contrôle d'accès. ([class.access]), aucun des membres n'est un sous-objet de taille zéro et leur classe n'est pas une union. 

Cette règle ne concerne que les pointeurs sur les membres de données du même objet, et non d'un objet différent.

(4.3) Sinon, aucun pointeur n'est requis pour comparer plus grand que l'autre.

Ainsi, vous n’obtenez aucune garantie de la norme. Une autre question est de savoir si vous pouvez trouver un système réel dans lequel vous obtenez un résultat différent de celui auquel vous vous attendez.

4
Max Langhof

Non, voici un contre-exemple

#include <iostream>

struct A
{
    int a_member[10];    
};

struct B : public virtual A
{
    int b_member[10];
    void print_b() { std::cout << static_cast<void*>(this) << " " << static_cast<void*>(std::addressof(this->a_member)) << " " << static_cast<void*>(this + 1) << std::endl; }
};

struct C : public virtual A
{
    int c_member[10];    
    void print_c() { std::cout << static_cast<void*>(this) << " " << static_cast<void*>(std::addressof(this->a_member)) << " " << static_cast<void*>(this + 1) << std::endl; }
};

struct D : public B, public C 
{
    void print_d() 
    { 
        print_b();
        print_c();
    }
};

int main()
{
    D d;
    d.print_d();
}

Avec la sortie possible (comme vu ici )

0x7fffc6bf9fb0 0x7fffc6bfa010 0x7fffc6bfa008
0x7fffc6bf9fe0 0x7fffc6bfa010 0x7fffc6bfa038

Notez que le a_member est en dehors de la B désignée par this dans print_b

0
Caleth

La valeur d'un objet est dans sa représentation, et cette représentation est une séquence de caractères non signés: [basic.types]/4

La représentation d'objet d'un objet de type T est la séquence de N objets char non signés repris par l'objet de type T, où N est égal à sizeof (T) . La représentation de la valeur d'un objet de type T est l'ensemble des bits qui participent à la représentation d'une valeur de type T. [...]

Donc, pour les fondamentalistes du formalisme, il est vrai que value n'est pas défini, mais le terme apparaît dans la définition de access: [defns.access] :

lire ou modifier la valeur d'un objet

La valeur d'un sous-objet fait-elle donc partie de la valeur d'un objet complet? Je suppose que c'est ce que vise la norme.

La comparaison doit être vraie si vous transformez les pointeurs d'objet en unsigned char*. (Il s'agit d'une pratique courante qui repose sur une sous-spécification problème fondamental n ° 1701 )

0
Oliv