Il y a quelque temps, je suis tombé sur du code qui marquait une variable membre d'une classe avec le mutable
mot - clé. Pour autant que je sache, cela vous permet simplement de modifier une variable dans une const
méthode:
class Foo
{
private:
mutable bool done_;
public:
void doSomething() const { ...; done_ = true; }
};
Est-ce la seule utilisation de ce mot-clé ou y a-t-il plus que ce qui semble évident? Depuis, j'ai utilisé cette technique dans une classe, marquant une boost::mutex
fonction mutable permettant const
de la verrouiller pour des raisons de sécurité des threads, mais, pour être honnête, cela ressemble à un hack.
mutable
: stackoverflow.com/questions/15999123/…const
(des types), donc je n'ai pas à le faireclass A_mutable{}; using A = A_mutable const; mutable_t<A> a;
:, si je veux const-by-default, c'est-à-diremutable A a;
(mutable explicite) etA a;
(const implicite).Réponses:
Il permet la différenciation de const au niveau du bit et de const logique. La const logique est lorsqu'un objet ne change pas d'une manière visible à travers l'interface publique, comme votre exemple de verrouillage. Un autre exemple serait une classe qui calcule une valeur la première fois qu'elle est demandée et met en cache le résultat.
Puisque c ++ 11
mutable
peut être utilisé sur un lambda pour indiquer que les choses capturées par valeur sont modifiables (elles ne le sont pas par défaut):la source
x
dans le lambda reste dans le lambda, c'est-à-dire que la fonction lambda ne peut modifier que sa propre copie dex
. Le changement n'est pas visible à l'extérieur, l'originalx
est toujours inchangé. Considérez que les lambdas sont implémentés en tant que classes de foncteurs; les variables capturées correspondent aux variables membres.Le
mutable
mot-clé est un moyen de percer leconst
voile que vous drapez sur vos objets. Si vous avez une référence const ou un pointeur vers un objet, vous ne pouvez en aucun cas modifier cet objet sauf quand et comment il est marquémutable
.Avec votre
const
référence ou votre pointeur, vous êtes contraint de:const
.Grâce à l'
mutable
exception, vous pouvez désormais écrire ou définir des membres de données marquésmutable
. C'est la seule différence visible de l'extérieur.En interne, les
const
méthodes visibles par vous peuvent également écrire sur les membres de données marquésmutable
. Essentiellement, le voile const est percé de manière complète. Il appartient entièrement au concepteur d'API de s'assurer quemutable
cela ne détruit pas leconst
concept et n'est utilisé que dans des cas spéciaux utiles. Lemutable
mot-clé est utile car il marque clairement les membres de données qui sont soumis à ces cas particuliers.En pratique, vous pouvez utiliser de manière
const
obsessionnelle tout au long de votre base de code (vous voulez essentiellement "infecter" votre base de code avec leconst
"maladie"). Dans ce monde, les pointeurs et les références sontconst
à de très rares exceptions près, produisant un code plus facile à raisonner et à comprendre. Pour une digression intéressante, recherchez "transparence référentielle".Sans le
mutable
mot - clé, vous serez éventuellement contraint d'utiliserconst_cast
pour gérer les différents cas spéciaux utiles qu'il permet (mise en cache, comptage de références, données de débogage, etc.). Malheureusement, ilconst_cast
est beaucoup plus destructeur quemutable
parce qu'il oblige le client API à détruire laconst
protection des objets qu'il utilise. De plus, il provoque uneconst
destruction généralisée :const_cast
un pointeur ou une référence const permet une écriture et une méthode d'appel sans entrave donnant accès aux membres visibles. En revanche,mutable
le concepteur d'API doit exercer un contrôle fin sur lesconst
exceptions, et généralement ces exceptions sont masquées dansconst
méthodes fonctionnant sur des données privées.(NB je me réfère à la visibilité des données et des méthodes à quelques reprises. Je parle des membres marqués comme public vs privé ou protégé qui est un type totalement différent de protection d'objet discuté ici .)
la source
const_cast
pour modifier une partie d'unconst
objet donne un comportement indéfini.const_cast
pour implémenter la mutation des variables membres dans uneconst
méthode, vous ne demanderiez pas au client de faire le cast - vous le feriez dans la méthode enconst_cast
ingthis
. Fondamentalement, il vous permet de contourner la constance sur des membres arbitraires sur un site d'appels spécifique , toutmutable
en vous permettant de supprimer const sur un membre spécifique sur tous les sites d'appels. Ce dernier est généralement ce que vous voulez pour une utilisation typique (mise en cache, statistiques), mais parfois le const_cast correspond au modèle.const_cast
modèle s'adapte mieux dans certains cas, comme lorsque vous souhaitez modifier temporairement un membre, puis le restaurer (à peu près commeboost::mutex
). La méthode est logiquement constante car l'état final est le même que celui initial, mais vous souhaitez effectuer ce changement transitoire.const_cast
peut être utile car il vous permet de supprimer const spécifiquement dans cette méthode si vous la mutation sera annulée, maismutable
ne serait pas aussi approprié car il supprimerait la protection const de toutes les méthodes, qui ne suivent pas nécessairement toutes le "do" , annuler "modèle.const_cast
une bombe à retardement possible.mutable
n'a pas un tel problème car de tels objets n'ont pas pu être placés en mémoire morte.Votre utilisation avec boost :: mutex est exactement à quoi ce mot-clé est destiné. Une autre utilisation est la mise en cache des résultats internes pour accélérer l'accès.
Fondamentalement, «mutable» s'applique à tout attribut de classe qui n'affecte pas l'état visible de l'extérieur de l'objet.
Dans l'exemple de code dans votre question, mutable peut être inapproprié si la valeur de done_ affecte l'état externe, cela dépend de ce qui est dans le ...; partie.
la source
Mutable sert à marquer un attribut spécifique comme modifiable à partir de
const
méthodes internes . C'est son seul but. Réfléchissez bien avant de l'utiliser, car votre code sera probablement plus propre et plus lisible si vous modifiez la conception plutôt que de l'utilisermutable
.http://www.highprogrammer.com/alan/rants/mutable.html
Les exemples que l'auteur donne incluent la mise en cache et les variables de débogage temporaires.
la source
mutable
peut rendre le code plus lisible et plus propre. Dans l'exemple suivant, leread
peut êtreconst
comme prévu. `m_mutex mutable; Container m_container; void add (Item item) {Lockguard lock (m_mutex); m_container.pushback (élément); } Élément read () const {Lockguard lock (m_mutex); return m_container.first (); } `Il est utile dans les situations où vous avez caché un état interne tel qu'un cache. Par exemple:
Et puis, vous pouvez faire en sorte qu'un
const HashTable
objet utilise toujours salookup()
méthode, qui modifie le cache interne.la source
mutable
existe comme vous le déduisez pour permettre de modifier les données dans une fonction par ailleurs constante.L'intention est que vous puissiez avoir une fonction qui "ne fait rien" à l'état interne de l'objet, et donc vous marquez la fonction
const
, mais vous devrez peut-être vraiment modifier certains des objets de manière à ne pas affecter son bon Fonctionnalité.Le mot-clé peut agir comme un indice pour le compilateur - un compilateur théorique pourrait placer un objet constant (tel qu'un global) dans la mémoire qui a été marqué en lecture seule. La présence d'
mutable
indices que cela ne devrait pas être fait.Voici quelques raisons valables pour déclarer et utiliser des données mutables:
mutable boost::mutex
est parfaitement raisonnable.la source
const
(et une telle inspection réussira ou échouera indépendamment deconst
oumutable
). Déclarer simplement la fonctionconst
ne suffit pas: uneconst
fonction est libre d'avoir des effets secondaires tels que la modification d'une variable globale ou quelque chose passée à la fonction, donc ce n'est pas une garantie utile pour cette preuve.const
mot clé en C ++.Eh bien, oui, c'est ce que ça fait. Je l'utilise pour les membres modifiés par des méthodes qui ne changent pas logiquement l'état d'une classe - par exemple, pour accélérer les recherches en implémentant un cache:
Maintenant, vous devez l'utiliser avec précaution - les problèmes de concurrence sont une grande préoccupation, car un appelant peut supposer qu'ils sont sûrs pour les threads uniquement en utilisant des
const
méthodes. Et bien sûr, la modification desmutable
données ne devrait pas changer le comportement de l'objet de manière significative, quelque chose qui pourrait être violé par l'exemple que j'ai donné si, par exemple, on s'attendait à ce que les modifications écrites sur le disque soient immédiatement visibles par l'application .la source
Mutable est utilisé lorsque vous avez une variable à l'intérieur de la classe qui n'est utilisée que dans cette classe pour signaler des choses comme par exemple un mutex ou un verrou. Cette variable ne modifie pas le comportement de la classe, mais est nécessaire pour implémenter la sécurité des threads de la classe elle-même. Ainsi, sans "mutable", vous ne pourriez pas avoir de fonctions "const" car cette variable devra être modifiée dans toutes les fonctions disponibles pour le monde extérieur. Par conséquent, mutable a été introduit afin de rendre une variable membre accessible en écriture même par une fonction const.
la source
mutable est principalement utilisé sur un détail d'implémentation de la classe. L'utilisateur de la classe n'a pas besoin de le savoir, donc la méthode qu'il pense "devrait" être const peut l'être. Votre exemple d'avoir un mutex mutable est un bon exemple canonique.
la source
Votre utilisation de celui-ci n'est pas un hack, bien que comme beaucoup de choses en C ++, mutable peut être piraté pour un programmeur paresseux qui ne veut pas revenir en arrière et marquer quelque chose qui ne devrait pas être const comme non-const.
la source
Utilisez "mutable" lorsque pour des choses qui sont LOGICALEMENT sans état pour l'utilisateur (et doivent donc avoir des getters "const" dans les API de la classe publique) mais ne sont PAS sans état dans la MISE EN ŒUVRE sous-jacente (le code dans votre .cpp).
Les cas où je l'utilise le plus souvent sont l'initialisation paresseuse de membres "sans données anciennes" sans état. À savoir, il est idéal dans les cas étroits où de tels membres sont coûteux à construire (processeur) ou à transporter (mémoire) et de nombreux utilisateurs de l'objet ne les demanderont jamais. Dans cette situation, vous voulez une construction paresseuse à l'arrière pour les performances, car 90% des objets construits n'auront jamais besoin de les construire, mais vous devez toujours présenter la bonne API sans état pour la consommation publique.
la source
Mutable change la signification de
const
const au niveau du bit en const logique pour la classe.Cela signifie que les classes avec des membres mutables sont plus constantes au niveau du bit et n'apparaissent plus dans les sections en lecture seule de l'exécutable.
De plus, il modifie la vérification de type en permettant
const
aux fonctions membres de changer les membres mutables sans utiliserconst_cast
.Voir les autres réponses pour plus de détails, mais je voulais souligner que ce n'est pas seulement pour la sécurité de type et qu'il affecte le résultat compilé.
la source
Dans certains cas (comme les itérateurs mal conçus), la classe doit garder un décompte ou une autre valeur incidente, qui n'affecte pas vraiment le "principal" état de la classe. C'est le plus souvent où je vois mutable utilisé. Sans mutable, vous seriez obligé de sacrifier toute la constance de votre conception.
Cela ressemble aussi à un hack la plupart du temps pour moi. Utile dans très très peu de situations.
la source
L'exemple classique (comme mentionné dans d'autres réponses) et la seule situation dans laquelle j'ai vu le
mutable
mot - clé utilisé jusqu'à présent est la mise en cache du résultat d'uneGet
méthode compliquée , où le cache est implémenté en tant que membre de données de la classe et non en tant que variable statique dans la méthode (pour des raisons de partage entre plusieurs fonctions ou de propreté absolue).En général, les alternatives à l'utilisation du
mutable
mot-clé sont généralement une variable statique dans la méthode ou l'const_cast
astuce.Une autre explication détaillée se trouve ici .
la source
const_cast
n'est que lorsque vous savez (ou avez été garanti) que quelque chose ne sera pas modifié (par exemple lors d'interférences avec les bibliothèques C) ou lorsque vous savez qu'il n'a pas été déclaré const. C'est-à-dire que la modification d'une variable const const castée entraîne un comportement indéfini.const_cast
peut être utilisé pour modifier un membre de classe dans uneconst
méthode, ce à quoi je faisais référence ...const_cast
, comme dit, cela n'est autorisé que lorsque l'objet n'a pas été déclaréconst
. Par exempleconst Frob f; f.something();
, avec desvoid something() const { const_cast<int&>(m_foo) = 2;
résultats dans un comportement indéfini.Le mutable peut être pratique lorsque vous remplacez une fonction virtuelle const et que vous souhaitez modifier votre variable membre de classe enfant dans cette fonction. Dans la plupart des cas, vous ne voudriez pas modifier l'interface de la classe de base, vous devez donc utiliser votre propre variable membre mutable.
la source
Le mot clé mutable est très utile lors de la création de stubs à des fins de test de classe. Vous pouvez stub une fonction const et toujours être en mesure d'augmenter les compteurs (mutables) ou n'importe quelle fonctionnalité de test que vous avez ajoutée à votre stub. Cela conserve l'interface de la classe tronquée intacte.
la source
L'un des meilleurs exemples où nous utilisons mutable est, en copie profonde. dans le constructeur de copie, nous envoyons
const &obj
comme argument. Le nouvel objet créé sera donc de type constant. Si nous voulons changer (surtout nous ne changerons pas, dans de rares cas nous pouvons changer) les membres de cet objet const nouvellement créé, nous devons le déclarer commemutable
.mutable
La classe de stockage ne peut être utilisée que sur un membre de données non statique et non const d'une classe. Le membre de données mutable d'une classe peut être modifié même s'il fait partie d'un objet déclaré comme const.Dans l'exemple ci-dessus, nous pouvons changer la valeur de la variable membre
x
bien qu'elle fasse partie d'un objet qui est déclaré const. En effet, la variablex
est déclarée comme mutable. Mais si vous essayez de modifier la valeur de la variable membrey
, le compilateur lèvera une erreur.la source
Le mot-clé même "mutable" est en fait un mot-clé réservé. Souvent, il est utilisé pour faire varier la valeur d'une variable constante. Si vous voulez avoir plusieurs valeurs d'une constante, utilisez le mot-clé mutable.
la source