OVH Cloud OVH Cloud

pb mutable

4 réponses
Avatar
beny78
Bonjour,

je fais des =E9volutions dans une code qui n'est pas le mien et je
rencontre quelque probl=E8mes.
j'ai une classe A et j'aimerai passer en arguments de fonction un
"const &"/"const *" (peu importe) sur une instance de cette classe.

ex :

class A
{
private:
std::map<....>* map //attribut

std::map<...>* get() //si map n'existe pas alors appel de load

load() // faite un new std::map<...>
};

Donc dans ma fonction qui a en arguements const A& / const A* et
comme get() n'est pas const je me fais jetter par le compilo.

donc il faut le passer en const, du coup j'ai mis map en mutable, mais
ce ne change rien.
il aurais fallut de get() fasse un new map pour que se soit bon :( or
il appelle load qui n'est pas une fonction const )

il y a-t-il une solution =E9l=E9gante.

Sinon je cast mon "const A*" en "A*" lorsque j'appelle get().

merci.

4 réponses

Avatar
Fabien LE LEZ
On 19 Oct 2006 08:05:37 -0700, "beny78" :

std::map<....>* map //attribut


Utiliser un nom existant pour une variable est une très mauvaise idée.
C'est même à la limite de l'obfuscation.

il aurais fallut de get() fasse un new map pour que se soit bon :( or
il appelle load qui n'est pas une fonction const )


Est-ce que "load()" modifie une variable membre non mutable, ou
appelle une fonction non-const ?
Si la réponse est "non", cette fonction peut être déclarée "const".

Avatar
Manuel Zaccaria
beny78 a écrit:
Bonjour,

je fais des évolutions dans une code qui n'est pas le mien et je
rencontre quelque problèmes.
j'ai une classe A et j'aimerai passer en arguments de fonction un
"const &"/"const *" (peu importe) sur une instance de cette classe.

ex :

class A
{
private:
std::map<....>* map //attribut

std::map<...>* get() //si map n'existe pas alors appel de load

load() // faite un new std::map<...>
};

Donc dans ma fonction qui a en arguements const A& / const A* et
comme get() n'est pas const je me fais jetter par le compilo.

donc il faut le passer en const, du coup j'ai mis map en mutable, mais
ce ne change rien.
il aurais fallut de get() fasse un new map pour que se soit bon :( or
il appelle load qui n'est pas une fonction const )

il y a-t-il une solution élégante.

Sinon je cast mon "const A*" en "A*" lorsque j'appelle get().

merci.


Je sais pas si c'est vraiment une bonne idée mais des fois on
a pas le choix...

si get est déclaré const et qu'on doit appeler load qui ne
l'est pas, on peut faire un truc comme ça :

class A
{
// ...

void load()
{
map_ = ...;
}

std::map<...>* get() const
{
if(!map_)
{
const_cast<A*>(this)->load();
}
return map_;
}
};


-
Manuel Zaccaria

Avatar
kanze
beny78 wrote:

je fais des évolutions dans une code qui n'est pas le mien et je
rencontre quelque problèmes.
j'ai une classe A et j'aimerai passer en arguments de fonction un
"const &"/"const *" (peu importe) sur une instance de cette classe.

ex :

class A
{
private:
std::map<....>* map //attribut

std::map<...>* get() //si map n'existe pas alors appel de load

load() // faite un new std::map<...>
};

Donc dans ma fonction qui a en arguements const A& / const A*
et comme get() n'est pas const je me fais jetter par le
compilo.

donc il faut le passer en const, du coup j'ai mis map en mutable, mais
ce ne change rien.


Certes. Parce que ce n'est pas get() qui modifie map, mais load.

il aurais fallut de get() fasse un new map pour que se soit bon :( or
il appelle load qui n'est pas une fonction const )

il y a-t-il une solution élégante.


Je suppose que ce que tu implémentes en fait, c'est le
chargement paresseux, et que conceptuellement, le map est const,
et ne varie jamais. (C-à-d que vu de l'extérieur, on voit
toujours le même contenu. Dans ce cas-là, je ne vois pas
pourquoi « load » ne serait pas const ; de même que get(), il
ne modifie pas la valeur de la classe vue de l'extérieur. Même
si le map n'est pas const, si le load n'est qu'un chargement
paresseux de la valeur initiale (persistente), je dirais qu'elle
est conceptuellement const, et qu'on pourrait donc la déclarer
const.

Mais j'ai des petites doutes par ailleurs :

-- get() renvoie un pointeur non const au map. C-à-d que le
client pourrait modifier le map, même si il n'en detient
qu'un pointeur vers const. La solution classique, ici, c'est
d'avoir deux fonctions, une const, qui renvoie un pointeur à
const, et l'autre non-const, qui renvoie un pointeur à non
const. Mais...

-- Est-ce que le fait d'exposer le map comme ça ne brise pas
l'encapsulation trop ? Quel est l'intérêt de mettre le map
dans la classe, si n'importe qui peut le modifier n'importe
comment ?

Sinon je cast mon "const A*" en "A*" lorsque j'appelle get().


Au niveau du client, j'espère que non. À l'intérieur de get(),
en revanche, c'est une solution potentielle. C'est une solution
qui sert beaucoup, même, quand la fonction n'est pas triviale et
qu'il y a une version const et non-const, pour qu'une des
versions revoie simplement à l'autre.

--
James Kanze (GABI Software) email:
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
beny78
Tout d'abord, merci de vos réponses.
Et je tiens à ajouter que le code de la classe A n'est pas le mien.

Le get() fait en effet un chargement paresseux, donc conceptuellement
la
fonction get() est const. (Cette fonction devrait renvoyer une const
map<...>*, je vais d'ailleurs faire la modif).

Au niveau du client, j'espère que non.



bah en fait je pensais à cette solution :(
mais je vais le faire dans le get, c'est beaucoup plus propre et
transfomer le get en get() const.

Merci pour la solution.


beny78 wrote:

je fais des évolutions dans une code qui n'est pas le mien et je
rencontre quelque problèmes.
j'ai une classe A et j'aimerai passer en arguments de fonction un
"const &"/"const *" (peu importe) sur une instance de cette classe.

ex :

class A
{
private:
std::map<....>* map //attribut

std::map<...>* get() //si map n'existe pas alors appel de load

load() // faite un new std::map<...>
};

Donc dans ma fonction qui a en arguements const A& / const A*
et comme get() n'est pas const je me fais jetter par le
compilo.

donc il faut le passer en const, du coup j'ai mis map en mutable, mais
ce ne change rien.


Certes. Parce que ce n'est pas get() qui modifie map, mais load.

il aurais fallut de get() fasse un new map pour que se soit bon :( or
il appelle load qui n'est pas une fonction const )

il y a-t-il une solution élégante.


Je suppose que ce que tu implémentes en fait, c'est le
chargement paresseux, et que conceptuellement, le map est const,
et ne varie jamais. (C-à-d que vu de l'extérieur, on voit
toujours le même contenu. Dans ce cas-là, je ne vois pas
pourquoi « load » ne serait pas const ; de même que get(), il
ne modifie pas la valeur de la classe vue de l'extérieur. Même
si le map n'est pas const, si le load n'est qu'un chargement
paresseux de la valeur initiale (persistente), je dirais qu'elle
est conceptuellement const, et qu'on pourrait donc la déclarer
const.

Mais j'ai des petites doutes par ailleurs :

-- get() renvoie un pointeur non const au map. C-à-d que le
client pourrait modifier le map, même si il n'en detient
qu'un pointeur vers const. La solution classique, ici, c'est
d'avoir deux fonctions, une const, qui renvoie un pointeur à
const, et l'autre non-const, qui renvoie un pointeur à non
const. Mais...

-- Est-ce que le fait d'exposer le map comme ça ne brise pas
l'encapsulation trop ? Quel est l'intérêt de mettre le map
dans la classe, si n'importe qui peut le modifier n'importe
comment ?

Sinon je cast mon "const A*" en "A*" lorsque j'appelle get().


Au niveau du client, j'espère que non. À l'intérieur de get(),
en revanche, c'est une solution potentielle. C'est une solution
qui sert beaucoup, même, quand la fonction n'est pas triviale et
qu'il y a une version const et non-const, pour qu'une des
versions revoie simplement à l'autre.

--
James Kanze (GABI Software) email:
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