Affectation des membres dans une fonction const
-
22-09-2019 - |
Question
J'ai un membre de la classe myMember qui est myType pointeur. Je veux attribuer à ce membre dans une fonction qui est déclarée const. Je fais comme suit:
void func() const
{
...
const_cast<myType*>(myMember) = new myType();
...
}
Faire cela fonctionne très bien dans VC ++, mais GCC donne une erreur avec le message « lvalue requis comme opérande gauche d'affectation ».
Faire le membre mutable me permettent de supprimer simplement le const_cast et affecter la valeur. Cependant, je ne suis pas tout à fait sûr que cela vient avec d'autres effets secondaires.
Puis-je attribuer mon membre sans avoir à faire le membre mutable? Comment? Y a-t-il des effets secondaires à faire des membres mutable?
La solution
Le code ne fonctionnera pas réellement dans VC ++ - vous n'êtes pas mise à jour de la valeur (ou du moins il ne devrait pas), d'où l'avertissement du CCG. code correct est
const_cast<myType*&>(myMember) = new myType();
ou [de l'autre réponse, merci: P]:
const_cast<ThisType*>(this)->myMember = new myType();
Rendre mutable signifie effectivement que vous obtenez const_cast
s implicites dans les fonctions membres de const
, qui est généralement ce que vous devriez orienter vers quand vous vous trouvez faire des charges de const_cast
s sur this
. Il n'y a pas « effets secondaires à l'utilisation mutable » autre que cela.
Comme vous pouvez le voir dans les débats véhéments encerclant cette question, l'utilisation bon gré mal gré mutable
et beaucoup de const_cast
s peut certainement être des symptômes de mauvaises odeurs dans votre code. D'un point de vue conceptuel, coulée ou à l'aide constness loin mutable
peut avoir des conséquences beaucoup plus importantes. Dans certains cas, la bonne chose à faire peut-être changer la méthode non-const, à savoir posséder au fait qu'il modifie l'état.
Tout dépend de combien les questions const-exactitude dans votre contexte - vous ne voulez pas finir par mutable
juste sprinking autour comme la poussière de Pixie pour faire le travail de choses, mais mutable
est destiné à un usage si la partie ISNT membre de l'état observable de l'objet. La vue la plus stricte de const-exactitude détiendrait que pas un seul bit de l'état de l'objet peut être modifié (par exemple, cela pourrait être critique si vous êtes par exemple est en ROM ...) - dans ces cas, vous ne voulez pas tout constness être perdu. Dans d'autres cas, vous pourriez avoir un état externe stocké quelque part ouside de l'objet - par exemple, un cache spécifique thread qui doit également être pris en considération au moment de décider si elle est appropriée
Autres conseils
Ce scénario - un changement d'état interne encapsulé qui n'a pas d'impact état externe (par exemple des résultats de la mise en cache) -. Est exactement ce que le mot-clé mutable
est pour
const_cast
est presque toujours un signe d'échec de la conception. Dans votre exemple, que ce soit func()
ne doit pas être const
ou myMember
doit être mutable
.
Un appelant de func()
s'attendra à son objet de ne pas changer; mais cela signifie « ne pas changer d'une manière qu'elle peut remarquer »; c'est de ne pas changer son état externe. Si le changement myMember
ne change pas l'objet état extérieur, c'est-ce que le mot-clé mutable
est pour; sinon, func()
ne doit pas être const
, parce que vous trahirais vos garanties de fonction.
Rappelez-vous que mutable
n'est pas un mécanisme pour circunvent const-exactitude; il est un mécanisme pour l'améliorer.
class Class{
int value;
void func()const{
const_cast<Class*>(this)->value=123;
}
};
Comme Steve Gilham a écrit, mutable
est la bonne réponse (et court) à votre question. Je veux juste vous donner un indice dans une autre direction.
Peut-être qu'il est possible dans votre Szenario d'utiliser une interface (ou plusieurs)?
Peut-être vous pouvez assimilez à partir de l'exemple suivant:
class IRestrictedWriter // may change only some members
{
public:
virtual void func() = 0;
}
class MyClass : virtual public IRestrictedWriter
{
public:
virtual void func()
{
mValueToBeWrittenFromEverybody = 123;
}
void otherFunctionNotAccessibleViaIRestrictedWriter()
{
mOtherValue1 = 123;
mOtherValue2 = 345;
}
...
}
Alors, si vous passez à une fonction d'un IRestrictedReader *
au lieu d'un const MyClass *
il peut appeler func
et donc changer mValueToBeWrittenFromEverybody
alors mOtherValue1
est une sorte de « const ».
. Je trouve mutable
toujours un peu un hack (mais parfois l'utiliser).