Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

[newbie] problème débile

64 réponses
Avatar
Azuriel
Est-ce possible de déclarer une propriété de même classe que celle qui
la possède ?

class A
{
A a;
};

ne compile pas.

10 réponses

1 2 3 4 5
Avatar
kanze
Azuriel wrote:
Azuriel wrote on 28/09/2006 19:34:
Est-ce possible de déclarer une propriété de même classe que celle
qui la possède ?

class A
{
A a;
};


Je suis vraiment trop con. C'est conceptuellement idiot ;)


non, ni idiot, ni inutile;


Si si, je voulais *vraiment* que A contient une instance de
lui-même en propriété et pas une référence ;). Quel idiot...

cela peut même être une façon de coder un noeud dans un
arbre ou une liste chainée (ok, depuis std::/set/ qui ferait
ça?).

l'auto-référencement impose simplement que la donnée membre
soit une référence ou un pointeur (les 2 valant pour un
pointeur de taille connu alors que la classe est de taille
inconnue lorsque la donnée 'a' est parsée - ce qui provoque
l'impossibilité de compiler).

donc:

class A {
A& a;
A(A another) : a(another) { ... }
};


Pour le cas du pointeur, c'est trivial, par contre pour les
références, j'aimerais un exemple qui compile dans ce cas et
utilisable car je n'y arrive pas.


class A
{
public:
A() : a( *this ) {}

private:
A& a ;
} ;

Quant à l'utilité, c'est autre chose:-). Dans la pratique, quand
on veut une référence au même type dans un objet, c'est pour la
navigation, et il faut pouvoir changer le référé dynamiquement.
Ce qui veut dire pointeur, et non référence.

Puisqu'il faut forcément fournir un nouveau A au constructeur
de A, comment créer un A "originel" sans rien lui fournir ?


Il y a toujours *this.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




Avatar
kanze
Sylvain wrote:
Azuriel wrote on 28/09/2006 20:17:

class A {
A& a;
A(A another) : a(another) { ... }
};


Pour le cas du pointeur, c'est trivial, par contre pour les référen ces,
j'aimerais un exemple qui compile dans ce cas et utilisable car je n'y
arrive pas.
Puisqu'il faut forcément fournir un nouveau A au constructeur de A,
comment créer un A "originel" sans rien lui fournir ?


;-) !

faute de pouvoir ne rien lui fournir, on peut lui fournir rien
en le faisant passer pour qlq chose ...

A* first = null;
A a(*first);

une référence (hormis la simplification syntaxique) est
l'équivalent d'un pointeur, donc on peut lui affecter une
valeur nulle (tester cette valeur ne conduira pas à un code
très clean mais bon ...).


D'où tu as ça ? Ce n'est pas du tout le cas en C++. Où ton
*first as déjà un comportement indéfini, et provoquait un core
dump avec au moins un compilateur dont je me suis servi.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
kanze
Sylvain wrote:
Michel Decima wrote on 28/09/2006 21:50:
Sylvain wrote:

faute de pouvoir ne rien lui fournir, on peut lui fournir rien en le
faisant passer pour qlq chose ...

A* first = null;
A a(*first);


Est ce que *first a un comportement defini si first vaut NULL ?


quelle importance puisqu'il N'est PAS déréférencé ...


Et c'est quoi, exactement, l'expression *first, si ce n'est pas
la déférencement de first.

Le comité est en train de revoir la question, je crois (qui se
présente dans des cas parfois inattendu), mais jusqu'à la
nouvelle version de la norme, au moin, c'est bien un
comportement indéfini. Et je me suis déjà servi d'au moins un
compilateur qui le vérifier lors de l'exécution, et qui
provoquait un core dump.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
Alexandre
class A
{
public:
A() : a( *this ) {}

private:
A& a ;
} ;

Quant à l'utilité, c'est autre chose:-). Dans la pratique, quand
on veut une référence au même type dans un objet, c'est pour la
navigation, et il faut pouvoir changer le référé dynamiquement.
Ce qui veut dire pointeur, et non référence.


je m'en suis servi une fois (pour un cas d'école il est vrai). Une classe
modélisant une personne, avec des références sur les parents (qui sont des
personnes). On peut bien sur prendre des pointeurs, mais ça me semblait plus
logique, la référence (les parents on les a depuis la naissance et ils ne
changent pas). Mais se posait alors le problème de la première personne...
et donc qui *doit* être son propre père et sa propre mère...

Avatar
dieu.tout.puissant
kanze wrote:
Sylvain wrote:
Michel Decima wrote on 28/09/2006 21:50:
Sylvain wrote:

faute de pouvoir ne rien lui fournir, on peut lui fournir rien en le
faisant passer pour qlq chose ...

A* first = null;
A a(*first);


Est ce que *first a un comportement defini si first vaut NULL ?


quelle importance puisqu'il N'est PAS déréférencé ...


Et c'est quoi, exactement, l'expression *first, si ce n'est pas
la déférencement de first.



*first n'implique pas forcément un déréférencement 'mécanique' du
pointeur first.

int *p = 0;

int &r = *p; // pas de déréférencement, seule l'adresse est
//utilisée => ok

int v = *p; // déréférencement => crash

La seconde ligne DOIT passer sur n'importe quel compilateur (warning au
maximum). Si vous connaissez un compilateur pour lequel cette ligne ne
passe pas, je serais intéressé d'en connaitre le nom.




Avatar
Michel Decima

*first n'implique pas forcément un déréférencement 'mécanique' du
pointeur first.

int *p = 0;

int &r = *p; // pas de déréférencement, seule l'adresse est
//utilisée => ok

int v = *p; // déréférencement => crash

La seconde ligne DOIT passer sur n'importe quel compilateur (warning au
maximum).


Qu'est ce qui JUSTIFIE cette affirmation dans la norme ?

Avatar
dieu.tout.puissant
Michel Decima wrote:

*first n'implique pas forcément un déréférencement 'mécanique ' du
pointeur first.

int *p = 0;

int &r = *p; // pas de déréférencement, seule l'adresse est
//utilisée => ok

int v = *p; // déréférencement => crash

La seconde ligne DOIT passer sur n'importe quel compilateur (warning au
maximum).


Qu'est ce qui JUSTIFIE cette affirmation dans la norme ?


L'opération d'initialisation d'une référence.
int &r = x;

2 cas :
- "x" est une lvalue ("x" doit être du type de la référence) :
l'opération d'initialisation prend l'adresse de "x" => "x" n'est pas
évalué.
- "x" est une rvalue ("x" ne doit pas forcément être du type de la
référence): Conversion implicite de type + création d'une variable
temporaire. => "x" est évalué. A partir de là, l'initialisation
possède un objet avec une adresse. Par conséquent, retour au premier
cas.

De plus, un comportement non défini devrait (mais ce n'est pas
toujours le cas...) générer de la part du compilateur uniquement un
warning.


Avatar
Michel Decima

L'opération d'initialisation d'une référence.
int &r = x;

2 cas :
- "x" est une lvalue ("x" doit être du type de la référence) :
l'opération d'initialisation prend l'adresse de "x" => "x" n'est pas
évalué.
- "x" est une rvalue ("x" ne doit pas forcément être du type de la
référence): Conversion implicite de type + création d'une variable
temporaire. => "x" est évalué. A partir de là, l'initialisation
possède un objet avec une adresse. Par conséquent, retour au premier
cas.


Si je considere

int& r = *(int*)0;

dans lequel des 2 cas on se place ? Quel devrait etre le resultat
de la compilation ?

Avatar
Falk Tannhäuser
schrieb:
L'opération d'initialisation d'une référence.
int &r = x;

2 cas :
- "x" est une lvalue ("x" doit être du type de la référence) :
l'opération d'initialisation prend l'adresse de "x" => "x" n'est pas
évalué.


Aaah Bon Dieu qui es aux cieux ! Faut-il vraiment que moi, un misérable
mortel, Vous cite l'Écriture Sainte - Psaume 8.3.2, Verset 4 :

[...] A reference shall be initialized to refer to a valid object or
function. Note: in particular, a null reference cannot exist in a
well-defined program, because the only way to create such a reference
would be to bind it to the “object” obtained by dereferencing a null
pointer, which causes undefined behavior. [...]

- "x" est une rvalue ("x" ne doit pas forcément être du type de la
référence): Conversion implicite de type + création d'une variable
temporaire. => "x" est évalué. A partir de là, l'initialisation
possède un objet avec une adresse. Par conséquent, retour au premier
cas.

De plus, un comportement non défini devrait (mais ce n'est pas
toujours le cas...) générer de la part du compilateur uniquement un
warning.


Ou une erreur, ou un plantage, ou un reformattage du disque dur, ou rien
du tout, ou une petite corruption de données de temps en temps...

Psaume 1.3.12 undefined behavior [defns.undefined]

Behavior, such as might arise upon use of an erroneous program construct
or erroneous data, for which this International Standard imposes no
requirements. Undefined behavior may also be expected when this
International Standard omits the description of any explicit definition
of behavior. [Note: permissible undefined behavior ranges from ignoring
the situation completely with unpredictable results, to behaving during
translation or program execution in a documented manner characteristic
of the environment (with or without the issuance of a diagnostic
message), to terminating a translation or execution (with the issuance
of a diagnostic message). Many erroneous program constructs do not
engender undefined behavior; they are required to be diagnosed. ]

Amen,
Falk

Avatar
dieu.tout.puissant
Michel Decima wrote:

L'opération d'initialisation d'une référence.
int &r = x;

2 cas :
- "x" est une lvalue ("x" doit être du type de la référence) :
l'opération d'initialisation prend l'adresse de "x" => "x" n'est pas
évalué.
- "x" est une rvalue ("x" ne doit pas forcément être du type de la
référence): Conversion implicite de type + création d'une variable
temporaire. => "x" est évalué. A partir de là, l'initialisation
possède un objet avec une adresse. Par conséquent, retour au premier
cas.


Si je considere

int& r = *(int*)0;

dans lequel des 2 cas on se place ? Quel devrait etre le resultat
de la compilation ?


*(int*) 0
Cette expression spécifie un objet de type int dont l'adresse est 0.
(<=> définition d'une lvalue)

Définition d'une lvalue dans la norme c++ :
lvalue : une expression qui réfère à un objet.
A un autre endroit, la norme utilise également cette définition
(équivalente dans la pratique):
lvalue : un objet dont on peut prendre l'adresse.

[Précision à ce sujet : la norme c++ indique clairement qu'une lvalue
n'est pas forcément un objet qui peut se placer à gauche de
l'opérateur d'assignement, tel qu'on l'entend souvent.]

L'expression est donc une lvalue.
Nous sommes dans le 1er cas.
Le compilateur devrait laisser passer cette ligne (il ne devrait pas
tenter un déréférencement).


1 2 3 4 5