OVH Cloud OVH Cloud

Questions tordues

14 réponses
Avatar
Aurélien REGAT-BARREL
Hello,
j'ai deux mini questions tordues:

namespace // anonyme
{
int a; // a1
}
int a; // a2

Pour désigner a2, on utilise ::a. Mais peut-on désigner a1 ?

est-ce que le code suivant est légal ?

int * i = new int[ 100 ];
char * c = reinterpret_cast<char*>( i );
delete [] c;

Merci.

--
Aurélien REGAT-BARREL

10 réponses

1 2
Avatar
Falk Tannhäuser
Aurélien REGAT-BARREL wrote:

namespace // anonyme
{
int a; // a1
}
int a; // a2

Pour désigner a2, on utilise ::a. Mais peut-on désigner a1 ?


Le namespace anonyme est équivalent à

namespace NomUniqueAuquelOnNAPasDAcces
{
int a;
}
using namespace NomUniqueAuquelOnNAPasDAcces;

il faudrait donc écrire "NomUniqueAuquelOnNAPasDAcces::a" pour résoud re
l'ambiguïté mais malheureusement on ne connaît pas "NomUniqueAuquel OnNAPasDAcces"...

est-ce que le code suivant est légal ?
int * i = new int[ 100 ];
char * c = reinterpret_cast<char*>( i );
delete [] c;


Non, voir § 5.3.5/3 :
"[...] In the second alternative (delete array) if the
dynamic type of the object to be deleted differs from
its static type, the behavior is undefined."

Falk

Avatar
Aurélien REGAT-BARREL
Falk Tannhäuser wrote:
Aurélien REGAT-BARREL wrote:

namespace // anonyme
{
int a; // a1
}
int a; // a2

Pour désigner a2, on utilise ::a. Mais peut-on désigner a1 ?


Le namespace anonyme est équivalent à

namespace NomUniqueAuquelOnNAPasDAcces
{
int a;
}
using namespace NomUniqueAuquelOnNAPasDAcces;

il faudrait donc écrire "NomUniqueAuquelOnNAPasDAcces::a" pour
résoudre
l'ambiguïté mais malheureusement on ne connaît pas
"NomUniqueAuquelOnNAPasDAcces"...


Ok.


est-ce que le code suivant est légal ?
int * i = new int[ 100 ];
char * c = reinterpret_cast<char*>( i );
delete [] c;


Non, voir § 5.3.5/3 :
"[...] In the second alternative (delete array) if the
dynamic type of the object to be deleted differs from
its static type, the behavior is undefined."

Falk


Je m'en doutais, mais, _apparement_, ça pose pas de problème dans le test
que j'ai fait, ça m'a surpris.

Bon allez, une dernière pour la route:

class A
{
private:
typedef int MonType1; // types privés
class MonType2 {};

public:
void Test1( MonType1 );
void Test2( MonType2 * );
};

A a;
a.Test1( 0 );
a.Test2( 0 );

je suis étonné que ça marche, vu que dans la définition d'une fonction
publique j'utilise un type privé. Pour le typedef je pense qu'il y a une
histoire d'alias, mais pour Test2, j'ai un cast implicite en MonType2 * qui
est fait, hors je n'ai pas le droit d'utiliser MonType2.
surtout que je découvre une nuance entre le bon vieux cast C qui est
interdit (?) et static_cast / reinterpret_cast (!) qui sont eux autorisés:

a.Test2( static_cast<A::MyType *>( 0 ) ); // OK
a.Test2( reinterpret_cast<A::MyType *>( 10 ) ); // OK
a.Test2( (A::MyType *)( 0 ) ); // ERREUR

Pourquoi le cast C++ est-il autorisé ?

--
Aurélien REGAT-BARREL


Avatar
Patrick 'Zener' Brunet
Bonsoir.

"Aurélien REGAT-BARREL" a écrit dans le
message de news: 42516fa1$0$12952$
[...]
Bon allez, une dernière pour la route:

class A
{
private:
typedef int MonType1; // types privés
class MonType2 {};

public:
void Test1( MonType1 );
void Test2( MonType2 * );
};

A a;
a.Test1( 0 );
a.Test2( 0 );

je suis étonné que ça marche, vu que dans la définition d'une fonction
publique j'utilise un type privé. Pour le typedef je pense qu'il y a une
histoire d'alias, mais pour Test2, j'ai un cast implicite en MonType2 *
qui

est fait, hors je n'ai pas le droit d'utiliser MonType2.
surtout que je découvre une nuance entre le bon vieux cast C qui est
interdit (?) et static_cast / reinterpret_cast (!) qui sont eux autorisés:

a.Test2( static_cast<A::MyType *>( 0 ) ); // OK
a.Test2( reinterpret_cast<A::MyType *>( 10 ) ); // OK
a.Test2( (A::MyType *)( 0 ) ); // ERREUR

Pourquoi le cast C++ est-il autorisé ?



Est-ce que ça ne serait pas un cas particulier lié au fait que le
compilateur utilise "int" par défaut pour se récupérer lorsqu'il se trouve
face à une déclaration manquante (ou inaccessible) ?

Par exemple, une faute de frappe dans le nom d'une constante d'enum conduit
à une tentative d'interprétation comme une variable typée "int" par
défaut...
Est-ce que le comportement est le même si MonType1 et MonType2 sont définis
pour ne pas être naturellement compatibles avec la constante 0 ?

Ou alors en invoquant avec une autre valeur :

private:
typedef char const MonType2;

puis

a.Test2( "prends toi ça !" );


Cordialement,

--

/***************************************
* Patrick BRUNET
* E-mail: lien sur http://zener131.free.fr/ContactMe
***************************************/

Avatar
Fabien LE LEZ
On Mon, 4 Apr 2005 18:55:48 +0200, "Aurélien REGAT-BARREL"
:

Je m'en doutais, mais, _apparement_, ça pose pas de problème dans le test
que j'ai fait, ça m'a surpris.


Ben oui, c'est un comportement indéfini : ça peut très bien marcher
pendant des mois, puis, au moment où tu fais une modification dans un
tout autre module, BOUM !

Cela dit, il y a une explication plus simple : pour les types de base,
delete[], delete et free() ont à peu près le même comportement : ils
se contentent de libérer la mémoire, sans appeler de destructeur.
Du coup, leur passer un pointeur "brut" (i.e. non typé, ou avec un
type fantaisiste) ne fait a priori pas planter le bazar -- ce qui ne
veut pas dire qu'il faut le faire ;-)

--
;-)

Avatar
Franck Branjonneau
"Aurélien REGAT-BARREL" écrivait:

class A
{
private:
typedef int MonType1; // types privés
class MonType2 {};

public:
void Test1( MonType1 );
void Test2( MonType2 * );
};

A a;
a.Test1( 0 );
a.Test2( 0 );

je suis étonné que ça marche, vu que dans la définition d'une fonction
publique j'utilise un type privé.


Mais tes appels de fonctions n'utilisent ni Montype1 ni Montype2 mais
0.

surtout que je découvre une nuance entre le bon vieux cast C


Il n'est pas bon, juste vieux.

qui est interdit (?)


Enlever le point d'interrogation.

et static_cast / reinterpret_cast (!)


Ajouter des points d'exclamations.

qui sont eux autorisés:

a.Test2( static_cast<A::MyType *>( 0 ) ); // OK
a.Test2( reinterpret_cast<A::MyType *>( 10 ) ); // OK
a.Test2( (A::MyType *)( 0 ) ); // ERREUR

Pourquoi le cast C++ est-il autorisé ?


Pour pouvoir t'aider il faudrait savoir ce qu'est MyType et d'où vient
ce fragment de code (fonction membre ou non). Quelle est l'erreur ?
--
Franck Branjonneau

Avatar
Falk Tannhäuser
Fabien LE LEZ wrote:
On Mon, 4 Apr 2005 18:55:48 +0200, "Aurélien REGAT-BARREL"
Je m'en doutais, mais, _apparement_, ça pose pas de problème dans le test
que j'ai fait, ça m'a surpris.
Ben oui, c'est un comportement indéfini : ça peut très bien marcher

pendant des mois, puis, au moment où tu fais une modification dans un
tout autre module, BOUM !


Ou quand on change de compilo, ou lorsqu'un jour on fait la même chose
avec des types ayant un destructeur non trivial, ou parce qu'on compile
une nuit de pleine lune, ou ...

Falk


Avatar
Fabien LE LEZ
On Tue, 05 Apr 2005 00:11:51 +0200, Falk Tannhäuser
:

ou parce qu'on compile
une nuit de pleine lune, ou ...


Évite de compiler les nuits de pleine lune, ou alors, assure-toi
d'avoir une gousse d'ail à portée de la main.


--
;-)

Avatar
Falk Tannhäuser
Franck Branjonneau wrote:
"Aurélien REGAT-BARREL" écrivait:
qui sont eux autorisés:

a.Test2( static_cast<A::MyType *>( 0 ) ); // OK
a.Test2( reinterpret_cast<A::MyType *>( 10 ) ); // OK
a.Test2( (A::MyType *)( 0 ) ); // ERREUR

Pourquoi le cast C++ est-il autorisé ?


Pour pouvoir t'aider il faudrait savoir ce qu'est MyType et d'où vient
ce fragment de code (fonction membre ou non). Quelle est l'erreur ?


Lorsque je mets MonType2 à la place de MyType, aucun de ces 3 casts
ne compile chez moi avec gcc 3.4.1 (dans un fonction non-membre -
en l'occurrence main()), tout comme il se doit.

Falk


Avatar
Samuel Krempp
le Tuesday 05 April 2005 00:23, écrivit :

On Tue, 05 Apr 2005 00:11:51 +0200, Falk Tannhäuser
:

ou parce qu'on compile
une nuit de pleine lune, ou ...


Évite de compiler les nuits de pleine lune, ou alors, assure-toi
d'avoir une gousse d'ail à portée de la main.


ah tiens donc, pour quoi faire ? il me semblait que l'ail repoussait les
vampires, et que ce sont les lycanthropes qui s'activent à la pleine lune.

--
Sam


Avatar
kanze
Aurélien REGAT-BARREL wrote:
Falk Tannhäuser wrote:
Aurélien REGAT-BARREL wrote:

est-ce que le code suivant est légal ?
int * i = new int[ 100 ];
char * c = reinterpret_cast<char*>( i );
delete [] c;


Non, voir § 5.3.5/3 :
"[...] In the second alternative (delete array) if the
dynamic type of the object to be deleted differs from
its static type, the behavior is undefined."


Je m'en doutais, mais, _apparement_, ça pose pas de problème
dans le test que j'ai fait, ça m'a surpris.


C'est le propre des comportements indéfinis. Ils peuvent marcher
de temps en temps aussi. Typiquement, ils marchent pendant tous
vos tests, mais provoquent un crash du système le jour de la
grande démo devant le client.

Bon allez, une dernière pour la route:

class A
{
private:
typedef int MonType1; // types privés
class MonType2 {};

public:
void Test1( MonType1 );
void Test2( MonType2 * );
};

A a;
a.Test1( 0 );
a.Test2( 0 );

je suis étonné que ça marche, vu que dans la définition d'une
fonction publique j'utilise un type privé.


Pourquoi pas ? Tu n'as utiliser que 0 (avec un type int).

En fait, à quelques exceptions près, les contrôles d'accès se
portent surtout sur les noms. L'exemple classique, c'est avec un
membre de donnée privé -- tu ne peux pas le nommer, pour y
accéder directement, mais tu peux bien y accéder à travers d'un
pointeur ou d'une référence, ou même d'un pointer à membre.

Pour le typedef je pense qu'il y a une histoire d'alias,


Tout à fait. La signature de la fonction contient « int » ; il
n'y a pas de type MonType1.

mais pour Test2, j'ai un cast implicite en MonType2 * qui est
fait, hors je n'ai pas le droit d'utiliser MonType2.


Tu n'a surtout pas droit à utiliser le nom MonType2. (C'est plus
complexe que ça, évidemment, mais en gros...) Mais par exemple,
tu aurais pu écrire :

class A
{
// comme ci-dessus ...
public:
static MonType2 x ;
static MonType2 y ;
} ;

a.Test2( &A::x ) ;

Tu n'a pas accès au type, mais tu as bien accès aux variables du
type, ou aux fonctions qui utilisent le type.

surtout que je découvre une nuance entre le bon vieux cast C
qui est interdit (?) et static_cast / reinterpret_cast (!) qui
sont eux autorisés:

a.Test2( static_cast<A::MyType *>( 0 ) ); // OK
a.Test2( reinterpret_cast<A::MyType *>( 10 ) ); // OK
a.Test2( (A::MyType *)( 0 ) ); // ERREUR


Je suppose que tu veux dire A::MonType2 dans tous les casts.
Sinon, je ne connais pas de compilateur qui accepterai aucun des
trois.

Pourquoi le cast C++ est-il autorisé ?


Parce qu'il y a un bug dans ton compilateur ?

En gros (et peut-être à des exceptions près), ce que fait le
complateur, c'est :

-- il recherche le nom que tu as écris, et le « lie » à une
déclaration, sans tenir compte de l'accès,

-- il vérifie l'accès -- si tu n'y a pas le droit, c'est une
erreur, et finalement,

-- il interprète la sémantique de ce que tu as écris.

La première phase comprend aussi la résolution du surcharge, le
cas échéant.

Note bien comment ça s'applique à ton exemple « a.Test2( 0 ) ».
Il n'y a aucun problème avec la première phase, évidemment ; le
compilateur trouve des liaisons (des « bindings ») non ambigus
pour tous les symboles dans l'expression. Ni avec la deuxième,
non plus -- tous les liaisons s'attache à des noms publiques.
Dans la troisième phase, il interprète la sémantique, ce qui
fait bien intervenir le type MonType2, mais il a déjà fini avec
la vérification des accès. Et lui (le compilateur), évidemment,
connaît MonType2. Donc, pas de problème.

Quand tu écris la conversion de façon explicite, c'est autre
chose. Le compilateur fait bien la recherche et la liaison du
nom MonType2, et alors, ensuite, il vérifie les droits d'accès.
Et puisque tu n'as pas le droit d'utiliser ce symbol, il râle.
Ou au moins, il doit râler.

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



1 2