OVH Cloud OVH Cloud

[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
Michel Decima

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).



Je connais au moins un compilateur qui refuse ce code. Si vous pensez
que cela n'est pas conforme, je vous laisse l'honneur du bug report.

http://www.comeaucomputing.com/tryitout/

Comeau C/C++ 4.3.8 (Aug 19 2006 13:36:48) for ONLINE_EVALUATION_Alpha1
Copyright 1988-2006 Comeau Computing. All rights reserved.
MODE:strict errors C++

"ComeauTest.c", line 2: error: NULL reference is not allowed
int& ref = *(int*)0;


Avatar
dieu.tout.puissant
Falk Tannhäuser wrote:
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. [...]



Je parle plus haut de déréférencement "mécanique". A aucun moment
dans la norme est-il écrit qu'une initialisation de référence
nécessite que l'objet référencé(de type lvalue) soit évalué. Le
compilateur ne produira donc pas un déréférencement de cet objet.

Notamment :
the only way to create such a reference
would be to bind it to the "object" obtained by dereferencing a null
pointer


Ce déréférencement "syntaxique" n'implique pas de déréférenceme nt
"mécanique" (c'est-à-dire l'accès à l'objet référencé).

Je réitère donc ma demande : si vous connaissez un compilateur qui
produit un déréférencement "mécanique" lors de l'opération
d'initialisation de la référence, merci de m'en donner le nom, je
n'en ai encore rencontré aucun, même en se basant une version debug
du code.

- "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. ]


La manière de prendre en charge un comportement non défini n'est
qu'une opinion de ma part (d'où l'utilisation du conditionnel
"devrait" et non "doit"). Etant donné que je travaille beaucoup en asm
et c++ sur des développements bas niveau, je préfère qu'un
compilateur génère un warning plutôt qu'une interdiction(erreur).
Il est bien évident que ce comportement *peut* provoquer un plantage,
c'est bien pour cela que je préconise la génération d'un warning.
Malheureusement, la réalité est tout autre.


Avatar
Gabriel Dos Reis
writes:


[...]

| Le compilateur devrait laisser passer cette ligne (il ne devrait pas
| tenter un déréférencement).

Parce que ?
Avatar
Gabriel Dos Reis
writes:

| Je parle plus haut de déréférencement "mécanique".

?

-- Gaby
Avatar
dieu.tout.puissant
Michel Decima wrote:

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 lval ue
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).



Je connais au moins un compilateur qui refuse ce code. Si vous pensez
que cela n'est pas conforme, je vous laisse l'honneur du bug report.

http://www.comeaucomputing.com/tryitout/

Comeau C/C++ 4.3.8 (Aug 19 2006 13:36:48) for ONLINE_EVALUATION_Alpha1
Copyright 1988-2006 Comeau Computing. All rights reserved.
MODE:strict errors C++

"ComeauTest.c", line 2: error: NULL reference is not allowed
int& ref = *(int*)0;


Merci.

Cependant, ce compilateur traite spécialement cette ligne de code car
l'adresse de l'objet référencé est évaluable statiquement. Il
n'effectue donc pas de déréférencement. C'est pour cela que ma
parenthèse "(il ne devrait pas tenter un déréférencement)" ajoutée
à mon affirmation,au conditionnel, "Le compilateur devrait laisser
passer cette ligne", est importante.

En effet, le code suivant passe sur le même compilateur :
int *p = 0;
int &r = *p;

Comme je le dis depuis le début, logiquement, aucun compilateur ne
provoquera un déréférencement de l'objet (lvalue) lors de
l'initialisation d'une référence. Ce code seul passe donc sur
n'importe quel compilateur et ne crash pas à l'exécution.



Avatar
Sylvain
Michel Decima wrote on 17/10/2006 00:14:

Je connais au moins un compilateur qui refuse ce code. Si vous pensez
que cela n'est pas conforme, je vous laisse l'honneur du bug report.

Comeau C/C++ 4.3.8 (Aug 19 2006 13:36:48) for ONLINE_EVALUATION_Alpha1


un bug report sur une version d'éval ?!??
c'est payé combien par report ?

Sylvain.

Avatar
Sylvain
wrote on 17/10/2006 01:40:

Cependant, ce compilateur traite spécialement cette ligne de code car
l'adresse de l'objet référencé est évaluable statiquement.


tu veux dire: est évalué car est une valeur immédiate ?

il me semble bien d'ailleurs que j'avais indiqué:

struct A {
A& a
A(A& _a) : a(_a) {}
};
A* first = null;
A a(*first);

et non
A a(*NULL);

Ce code seul passe donc sur n'importe quel
compilateur et ne crash pas à l'exécution.


ce dont je suis persuadé.

Sylvain.

Avatar
dieu.tout.puissant
Gabriel Dos Reis wrote:
writes:

| Je parle plus haut de déréférencement "mécanique".

?

-- Gaby


C'est une expression que j'utilise mais qui n'est absolument pas
standardisée.
Voilà ce que j'entend par déréférencement mécanique :

int *i = new int(5);

L'expression *i est qualifiée de déréférencement du pointeur i. On
pourrait supposer que ce déréférencement accède à l'objet point é
(valeur 5), mais ce n'est pas toujours le cas : j'affirme que
l'expression *i utilisée lors d'une opération d'initialisation d'une
référence ne cause pas l'accès à i. D'ailleurs, j'ai toujours
constaté ce comportement en consultant le code généré par certains
compilateurs (sans ou avec optimisation).

Le déréférencement mécanique est donc l'accès à l'objet point é
et pas simplement la désignation de l'objet pointé.

Avatar
dieu.tout.puissant
Sylvain wrote:
wrote on 17/10/2006 01:40:

Cependant, ce compilateur traite spécialement cette ligne de code car
l'adresse de l'objet référencé est évaluable statiquement.


tu veux dire: est évalué car est une valeur immédiate ?


Oui, "est évaluable statiquement" dans le sens "est connu par le
compilateur" puisque valeur immédiate.


il me semble bien d'ailleurs que j'avais indiqué:

struct A {
A& a
A(A& _a) : a(_a) {}
};
A* first = null;
A a(*first);

et non
A a(*NULL);

Ce code seul passe donc sur n'importe quel
compilateur et ne crash pas à l'exécution.


ce dont je suis persuadé.

Sylvain.


Effectivement, ce code doit marcher.


Avatar
dieu.tout.puissant
wrote:
Gabriel Dos Reis wrote:
writes:

| Je parle plus haut de déréférencement "mécanique".

?

-- Gaby


C'est une expression que j'utilise mais qui n'est absolument pas
standardisée.
Voilà ce que j'entend par déréférencement mécanique :

int *i = new int(5);

L'expression *i est qualifiée de déréférencement du pointeur i. On


Je dois hélas apporter une précision : je parle de l'expression *i
qui serait utilisée -après- l'initialisation du pointeur i telle que
décrite plus haut, et non pas de *i -dans- l'initialisation du
pointeur. Voilà encore une confusion qui justifie l'usage de "int* i"
à la place de "int *i".


1 2 3 4 5