9
votes

Affectation des membres dans une fonction Const

J'ai un membre de la classe mymember em> c'est un pointeur mytype em>. Je veux affecter ce membre dans une fonction déclarée Const. Je fais comme suit:

void func() const
{
     ...
     const_cast<myType*>(myMember) = new myType();
     ...
}


0 commentaires

5 Réponses :


17
votes

Ce scénario - Un changement d'état interne encapsulé qui n'a pas d'impact sur l'état externe (par exemple les résultats de la mise en cache) - est exactement ce que le mot clé mutable est destiné.


2 commentaires

Mutable n'est pas bon si vous voulez obtenir un accès en écriture à un membre dans une seule méthode constante.


L'état observable à l'extérieur de l'objet ne doit pas changer lors de l'écriture sur un objet mutable. Faire un membre mutable juste pour contourner une erreur dans une fonction Const n'est pas légitime si le changement est visible de l'extérieur et peut conduire à un comportement non défini. Les utilisations légitimes d'un mutable incluent la mise en cache, où par exemple, le même appel reprend deux fois le même résultat, mais plus vite.



5
votes
class Class{
int value;
void func()const{
const_cast<Class*>(this)->value=123;
}
};

2 commentaires

Vous avez besoin d'un objet moulé au lieu d'un membre.


Merci. Je vais par le premier code de Ruben depuis qu'il a l'air plus propre. Si je pouvais, je marquerais comme "réponse".



8
votes

Le code ne fonctionne pas réellement en VC ++ - vous ne mettez pas à jour la valeur (ou au moins cela ne devrait pas), d'où l'avertissement de GCC. Le code correct est xxx

ou [à partir d'une autre réponse, merci: p]: xxx

la rendre mutable signifie efficacement "code > const_cast S dans Const Fonctions membres, qui est généralement ce que vous devriez vous diriger vers lorsque vous vous trouvez en train de faire des charges de const_cast S sur Ceci < / code>. Il n'y a pas de "effets secondaires à l'utilisation mutable" autre que cela.

Comme vous pouvez le constater sur les débats véhément à la suite de cette question, une utilisation willy-nilly de mutable et beaucoup de const_cast s peut certainement être des symptômes de mauvais sent votre code. D'un point de vue conceptuel, la consensions de la constance ou l'utilisation de mutable peut avoir des implications beaucoup plus importantes. Dans certains cas, la bonne chose à faire peut être de modifier la méthode à la non-const, c'est-à-dire que celle-ci est de modifier l'état.

Tout dépend de la quantité de constance importante dans votre contexte - vous ne voulez pas finir simplement par Sprinking mutable autour de la poussière de Pixie pour faire fonctionner des trucs, mais mutable est destiné à être utilisé si le membre n'a pas une partie de l'observable état de l'objet. La vue la plus stricte de la const-Cidressness conserve que non un seul bit de l'état de l'objet ne peut être modifié (par exemple, cela pourrait être essentiel si votre instance est en rom ...) - Dans ces cas, vous ne voulez pas de Conscience être perdu. Dans d'autres cas, vous pourriez avoir un état externe stocké quelque part d'ouside de l'objet - par exemple, un cache spécifique au fil qui doit également être pris en compte lors de la décision si elle est appropriée.


7 commentaires

Je pense que cela fonctionne que c'est peut-être la pire solution. Cela cache complètement ce qui se passe (changeant un état interne d'une instance immuable) dans une constance dans la fonction membre. "mutable" serait plus claire (ou utilise des interfaces).


La création de la constance conduit à un comportement indéfini. À utiliser à vos risques et périls. Une meilleure solution serait de faire la méthode non Const.


@Lokiastari Non, Casting Away Const NESS n'invoque pas UB - à moins que l'objet référé sous-jacent n'a été déclaré à l'origine const , un faux pas à l'IMO rend le programmeur méritant l'UB. Pour le reste, en référence aux objets qui n'étaient pas Const -qualifiés à leur déclaration, la création de const ness est parfaitement bien défini. Ici: Stackoverflow.com/a/3485333/2757035


@underscore_d Nope. Je n'ai jamais dit que c'était UB. J'ai dit qu'il conduit à UB. Si vous éloignez la Constance dans une méthode constante, vous risquez de causer une UB. Si vous ajoutez la Centaness dans une méthode sans coût, rien de mal ne se produira. Je me tiens à mon énoncé d'origine. Voir aussi: Stackoverflow.com/q/4042626/14065 Modification de tout objet où le const a été renvoyé " May " cause UB. Ce n'est peut-être pas qu'une implémentation conforme peut (ce qui permet certaines optimisations). Modification d'un objet qui était en réalité est définitivement ub.


@Lokiastari Votre utilisation de "mène à" est invisible - vous vouliez dire "rendre le programmeur susceptible de faire quelque chose de Daft", mais la plupart des gens vont lire cela comme "causes directement". Quoi qu'il en soit, nos deux liens proposent des citations suggérant que le résultat est défini, tant que l'objet d'origine n'était pas déclaré const . La citation d'ouverture de votre lien semble contredire cela - mais liens vers le même exemple que je cite . Je pense que c'est un autre morceau de formulation médiocre par la norme, mais, comme cela se passe pour citer un exemple défini d'un const_cast ED PTR modifiant un objet non const objet, doit Continuez à parier sur ma 1ère interprétation.


@underscore_d je suis en désaccord. Vous dites essentiellement que, dans certaines circonstances, la consensions est bien. Bien que techniquement correct, le point soit obtus (quand il y a une écriture impliquée) et donc je ne suis pas d'accord et que le code est fondamentalement cassé . À l'intérieur d'une méthode, il n'ya aucun moyen de dire si l'objet d'origine était constitué ou non et que vous jouez donc essentiellement de la roulette russe. Code qui est fragile et dépend des curcumstances pour être soit UB ou non est cassé. Alors oui, je ne le dis pas explicitement, j'insère très fortement que cela va faire sauter dans votre visage.


Le cependant que si j'ai un objet Const et appelez une méthode de const que mon code présentera UB ne devrait pas arriver. Je n'ai probablement pas écrit la méthode en question (j'utilise beaucoup de code d'autres personnes). Donc, avoir l'auteur crée des cours qui peuvent exploser mon code lorsque je l'appelle correctement est un comportement brisé. Ainsi, ma déclaration originale est debout.



6
votes

const_cast est presque toujours un signe de défaillance de la conception. Dans votre exemple, func () ne doit pas être const ou MyMember doit être mutable

Un appelant de Func () s'attendre à ce que son objet ne change pas; Mais cela signifie "ne pas changer d'une manière qu'elle peut remarquer"; C'est non plus de changer d'état externe. Si vous modifiez MyMember ne modifie pas l'état externe de l'objet, c'est ce que le mot clé mutable est pour; Sinon, func () ne doit pas être const , car vous trahissez vos garanties de fonction.

N'oubliez pas que mutable n'est pas un mécanisme de Circunvent Const-Constance; C'est un mécanisme pour l'améliorer.


3 commentaires

^ Oui, et parfois, l'échec est dans une bibliothèque que vous utilisez! J'utilise un qui prend un pointeur à non- const mais (et je vérifie cela régulièrement :) ne mutait pas l'objet. Sécuriser dans cette connaissance, je peux donc passer tout obj const & (y compris temporaire) à ladite bibliothèque, je l'enveloppe dans une fonction qui fait un const_cast (& consobj) < / code>. Moche, peut-être - mais plus vrai de la réalité de ce qui arrive réellement au obj et me permet de faire de meilleures choses avec la bibliothèque ... au moins jusqu'à ce que l'auteur décide d'utiliser C ++ plus que c [soupir]


@underscore_d c'est l'une des utilisations légitimes de const_cast : Traiter avec imperfecté C ++. Si j'avais un cent pour chaque ponter-to-non constitue qui devrait être un pointeur à Const dans le monde ...


@Gorpik à coup sûr. Comme un de côté, je me demande combien de ces problèmes sont causés par des personnes qui ne respectent tout simplement pas const -Correcness - et combien par des personnes essayant de mais pas d'utilisation de droite-to -Le ordre de déclaration limite ;-)



1
votes

As Steve Gilham écrit, mutable code> est la réponse correcte (et courte) à votre question. Je veux juste vous donner un indice dans une direction différente. Peut-être que c'est possible dans votre Szenario d'utiliser une interface (ou plus d'une)? Peut-être pouvez-vous le greffer à 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;
  }

  ...   
}


0 commentaires