De ma compréhension du mot clé mutable, une de ses utilisations principales est la mise en cache des données et l'informer en cas de besoin. Depuis qu'ils peuvent changer (même s'ils sont constants) ne serait-il pas dangereux ou inutile de les utiliser? La partie de mise en cache modifie les données afin qu'il y aurait besoin d'une serrure et de ma compréhension lorsque vous écrivez pour des multithreads, les données ne doivent jamais modifier et les copies doivent être effectuées et retournées / chaînées ensemble. P>
Il est donc inutile ou mauvais d'utiliser le mot-clé mutable C ++? P>
3 Réponses :
Non, le mot clé mutable est de sorte que vous puissiez avoir des champs à l'intérieur d'un objet pouvant changer même lorsque l'objet est constitué, tel que pour les métadonnées qui ne font pas partie des propriétés d'un objet, mais sa gestion (comme des comptoirs, etc. .). Il n'a rien à voir avec le filetage. P>
Le filetage est i> un problème ici. Si vous avez un certain nombre de threads, tous avec des références de const à un objet partagé, il est facile de supposer que tous ces threads peuvent appeler les fonctions de membre constant sur cet objet sans aucun type de synchronisation. Toutefois, s'il existe des éléments de données mutables modifiés par ces fonctions membres de Const, vous devez vous assurer que ces modifications sont correctement synchronisées.
Ce que je voulais dire, c'est que le mot clé lui-même n'a rien à voir avec le filetage, la manière dont une personne comme volatile code> fait. Et je jamais i> suppose que les méthodes d'appel sur un objet Const de deux threads fonctionne - non pas à cause de cela, mais en raison du fait que, tandis que, tandis que const code> signifie que l'objet ne signifie que l'objet 't Change, cela ne dit rien des objectifs de toutes les cibles ou des références qu'il pourrait avoir - afin que vous puissiez modifier quelque chose de mal à l'aide de références constantes sans données mutables.
Vous avez tort de mutable, il permet à Membres Vars marqués mutable d'être modifié dans des méthodes marquées Const, peu importe si l'instance qu'elles soient appelées est constituée ou non.
Hein? N'est-ce pas exactement ce que j'ai écrit dans mon post? ("Le mot clé mutable est de sorte que vous puissiez avoir des champs à l'intérieur d'un objet qui peut changer même lorsque l'objet est constitué ...")
Certainement, le problème est un problème conceptuel: il est assez facile de raisonner que (i) tous mes threads n'appellent que les fonctions de membre Const sur cet objet partagé, (ii) des fonctions membres de Conscons ne modifient pas l'objet sur lequel ils sont appelés, (III ) Si un objet n'est pas modifié, je n'ai pas besoin de synchroniser l'accès à celui-ci, donc (IIII), je n'ai pas besoin de synchroniser l'accès à l'objet. Cet argument est faux parce que (ii) est faux, mais c'est vraiment facile de penser que cet argument a raison.
@James: Vous avez raison que (ii) est faux, mais mon point est, ce n'est même pas à cause de cette raison. Même si mutable code> n'existait pas, et même si les champs de l'objet ne changent jamais, ce qu'ils point i> peuvent changer, et donc il n'est donc pas sûr d'utiliser Const code> pour multithreading, même si mutable code> n'a même pas existé.
(En outre, je ne me souviens pas si vous pouvez avoir des références const code> à des objets mutables ou non, mais je pense toujours à const code> en tant que const code> Voir i> d'un objet potentiellement mutable, pas un objet constant, pour les raisons ci-dessus, que ce soit ou non mutable code> existe.)
@Lambert: Oui, vous pouvez avoir une référence constante à un objet non-Const. Si je comprends bien votre commentaire correctement, vous affirmez que c'est une question plus fondamentale et que lorsque vous utilisez un objet de plusieurs threads, vous avez vraiment besoin d'une bonne compréhension de la garantie de la concurrence que cela garantit. Je suis d'accord avec ça, 100%. Je suppose que mon argument est plus difficile de ", il est potentiellement plus facile pour un utilisateur de la classe à bousiller s'il y a un état mutable caché, non synchronisé".
Exemple: si vous avez un écrivain de fichier code> const code>, vous ne pouvez pas supposer qu'il est synchronisé simplement car chaque champ (Poignée d'exploitation, etc.) est const code>, même s'il jamais i> changements - simplement parce que vous n'avez aucune idée de savoir si le pointe de la poignée est également constitué. (@James: Modifier, sur votre commentaire: Oui, c'est une question beaucoup plus fondamentale, et jusqu'à aujourd'hui, je n'ai même jamais vu les mots mutables code> ou const code> dans la même phrase Comme synchroniser i> ... Ils sont complètement différents et ne garantissent aucune garantie d'une autre, réelle ou imaginaire.)
-1. Pas parce que vous avez mal (votre droit, du moins dans ces commentaires). Mais je n'ai pas demandé si un mot clé mutable a quelque chose à voir avec le filetage. Juste si c'est mauvais de les utiliser avec une filetage.
@Lambert: Vous avez dit "même lorsque l'objet est Const" j'ai dit "même lorsque la méthode est constituée si l'objet est constitué ou non b>". Légère distinction, même si le ce pointeur est Const à l'intérieur d'une méthode du const.
Disons également que STL String Class utilise le mot clé mutable lors de l'appel C_STR (). Vous vous attendez à ce que II soit vrai parce que ce n'est pas quelque chose d'évident comme un tableau de const pointant vers (non correspondance). Vous pensez que sa chaîne constante ne change jamais.
+1 Parce que je suis d'accord avec votre raisonnement que c'est une question plus fondamentale. C'est juste un problème malheureux que de nombreuses personnes ne soient pas extrêmement prudentes lors de la rédaction de code multithreadé (bien sûr, je sais que j'ai fixé des bugs dans mon propre code aussi où je n'étais pas aussi prudent que j'aurais dû être).
@ ACIDEZOMBIE24: Eh bien, la réponse n'était pas "oui" ou "non" parce que vous semblez avoir mal compris le point de "mutable". Il est tout simplement sans rapport avec enfilage, cela n'affecte pas la bonne et la mauvaise ness du code. @Eugen: Je ne vois toujours rien de mal, même subtilement. Pourriez-vous s'il vous plaît clarifier ce qui est incorrect / incomplet sur ce que j'ai dit? @ ACIDEZOMBIE24: Le problème est que vous n'avez jamais jamais b> appelez une méthode sur un objet de deux threads à la fois, qu'il s'agisse ou non d'une constante, et de quoi ou non mutable code> existe.
Il est donc inutile ou mauvais d'utiliser le mot-clé mutable C ++? P> blockQuote>
non; Le mot clé
mutable code> est une bonne chose.mutable code> peut être utilisé pour séparer l'état observable d'un objet du contenu interne de l'objet. p>avec l'exemple "Données en cache" que vous décrivez (une utilisation très courante de
mutable code>), il permet à la classe d'effectuer des optimisations "sous les couvertures" qui ne modifient pas réellement l'état observable . p>En ce qui concerne l'accès à un objet de plusieurs threads, oui, vous devez faire attention. En général, si une classe est conçue pour être accessible à partir de plusieurs threads et il dispose de variables code> mutable de code>, il doit synchroniser la modification de ces variables en interne. Notez cependant que le problème est vraiment plus conceptuel. Il est facile de raisonner que: p>
- Tous mes threads n'appellent que les fonctions de membre constant sur cet objet partagé LI>
- Les fonctions de membre constant ne modifient pas l'objet sur lequel ils sont appelés li>
- Si un objet n'est pas modifié, je n'ai pas besoin de synchroniser l'accès à celui-ci Li>
- Par conséquent, je n'ai pas besoin de synchroniser l'accès à cet objet li> ol>
Cet argument est faux parce que (2) est faux: les fonctions membres de la const peuvent en effet modifier des membres de données mutables. Le problème est que c'est vraiment, vraiment facile de penser que cet argument a raison. P>
La solution à ce problème n'est pas facile: efficacement, il vous suffit d'être extrêmement prudent lors de la rédaction de code multithread et d'être absolument certain que vous comprenez soit comment les objets partagés entre les threads sont mis en œuvre ou quelles sont les garanties de la concurrence. < / p>
Si une classe est conçue pour être accessible à partir de plusieurs threads et que toutes les variables i> non constant, il doit synchroniser la modification de ces variables.
@CHARDLES: Eh bien, je pense que cela peut être affirmé que c'est plus un problème avec les membres de données code> mutables. Si vous avez un certain nombre de threads avec des références de const à un objet partagé, il est souvent raisonnable de supposer que vous pouvez appeler ces fonctions de membre de const sans aucune synchronisation. Il est facile d'oublier mutable et de penser de manière incorrecte que les fonctions des membres de Conscons ne peuvent pas du tout muté l'état sous-jacent.
@James: une règle que je suive toujours: si vos données immuables sont simplement que - immuables Data b> - alors votre "objet" n'avait plus de méthodes, et il vaut mieux avoir des membres qui sont mieux Tous Const et qui pointent transitivement vers des membres immuables. Si vous pouvez satisfaire ces conditions, n'hésitez pas à accéder à l'objet «Objet» (AKA Agrégate de données) sans serrures. Si votre code appelle toutes les méthodes i> sans serrures, le code est dangereux, quelles que soient les conditions.
@Lambert: Je pense que c'est un peu extrême. Par exemple, si vous avez une bibliothèque de conteneurs compatibles C ++ 0x, vous êtes garanti que vous pouvez itérer sur le conteneur simultanément tant que vous n'effectuez aucune opération invalidation des itérateurs (il pourrait y avoir plus de restrictions que cela; i ' M Non certain à 100% sur toutes les améliorations de la concurrence à la bibliothèque standard, mais c'est ce que je crois comprendre. J'aurais certainement davantage de recherches si je voulais compter sur cela.) Une classe peut fournir des guranties explicites sur sa convivialité simultanée.
@James: D'accord, c'est un peu extrême, car il y a une petite exception: "Sauf lorsque la classe explicitement i> garantit la sécurité du fil". Mais prenez cela avec prudence - I I> Seul i> Utilisez cette affirmation d'objets de wrapper dont le seul but est de fournir une sécurité de thread, car il n'y a pas à peu près tout à fait de faire de l'autre objet Thread-Safe-Safe - Plusieurs procédés sont presque toujours dangereux, même si le conteneur sous-jacent est sûr. (Par exemple: ajoutez un objet, puis retirez-le - même si chacun de ceux-ci est synchronisé, ils ne sont pas synchronisés ensemble, alors pourquoi verrouiller le conteneur à la fois interne et extérieurement?)
@James: Une fois encore je suis d'accord, bien que je sois encore plus précis. Même sans mutable, car const code> n'est pas propagé par des pointeurs (malheureusement?) const code> méthodes sur un objet peut réellement modifier son état. Que ce soit bon ou mauvais est argoutable, ce qui est certain que la langue le permettait et qu'il est laissé au développeur de bien réussir.
@Matthieu: Exactement - c'est pourquoi je considère que "const" est comme une limitation "autorisation" pour le spectateur plutôt qu'un contrat contraignant pour l'objet. Pour moi, cela signifie "vous ne pouvez pas écrire ici" plutôt que "ces données sont immuables".
@Lambert: En fait, il y a 2 utilisations. Certains utilisateurs utiliseront Const code> comme liaison (Constance physique), tandis que d'autres (comme moi) le préfèrent exprimer une conscience logique (sur l'état observable de l'objet) avec le raisonnement que l'état non observable (comme la mise en cache) est une implémentation de détail. Pour chacun ses sons, je suppose, mais mieux ne pas mélanger les deux concepts dans une base de code :)
@Matthieu: haha je vois ce que tu veux dire, mais je suppose que mon interprétation est le choix 3: c'est un drapeau de permission en lecture seule; Il ne dit rien sur la manière dont l'objet se comporte, à moins que ce soit de la POD sans pointers intégrés (et par conséquent, à moins que cela n'a pas de méthodes).
À propos, vous pourriez trouver Ce lien à propos de const contre immutable dans d a > intéressant.
@Lambert: BTW sur les méthodes et la pod. Certaines langues ont des méthodes sur Enums. Quelle est la plus étrange? J'ai cependant pensé que c'était bizarre puis trouvé une utilisation pour cela. Quoi qu'il en soit, je lis que D lien d maintenant et je pense que la pod et les classes doivent être considérés comme des choses différentes et avoir un nom différent. En règle générale, j'appelle des structures comme pod et classes comme des choses que je n'ai pas vraiment de grénage;)
@ acidzombie24: Ouais, les méthodes d'enum sont une sorte de bizarre, comme en Java (et peut-être de D, je ne suis pas sûr) ... Je peux les surmonter, car je n'ai pas encore vue une sorte de mutation sur n'importe quoi. Et oui, la POD n'est pas un très grand terme - en fait, je n'aime pas cela en C ++, les classes ne sont que des structures privées. Dans d'autres langues, il y a beaucoup de différences claires (par exemple c #, d) et uniquement des structures peuvent être une pod, pas des classes (bien que toute évidence, toutes les structures ne soient pas pod). Et j'aime votre dernière phrase, bien que je faire i> avez des matrices d'objets. :)
à l'extrémité opposée, la plupart de mon code multithreaded nécessite em> l'utilisation du mot clé code> mutable em>: Le fait que le fait que le Vous pouvez même créer l'attribut Le modificateur mutable code> mutable n'est pas un problème avec le code multithreadisé, uniquement lorsque vous essayez de Faites Lock-moins em> multithreading. Et comme avec tout programmation em> Lock-moins em>, vous devez être très em> prudent avec ce que vous faites, quel que soit le Obtenir la méthode code> ne modifie pas l'état de l'objet code> est déclaré au moyen du mot clé const code>. Mais sans le modificateur code> MAUTITABLE > appliqué à la déclaration de l'attribut mutex code>, le code ne pourrait pas verrouiller ni libérer les opérations Mutex --Both, clairement modifier < / em> le mutex code>, même s'ils ne modifient pas l'objet code>. p> data code> mutable si cela peut être évalué paresseusement et que le coût est élevé, tant que vous verrouillez l'objet. Ceci est l'utilisation em> cache em> que vous vous référez à la question. P> const code> ou mutable code>. Vous pouvez écrire un code multithreadisé parfaitement dangereux qui appelle les méthodes const code> sur des objets sans attributs code> mutable code>. L'exemple simple retirerait le mutex du code précédent et que n threads n'effectue que get () code> s tandis qu'un autre thread exécute Set () code> s. Le fait que get () code> est const n'est pas une garantie que vous ne recevrez pas de résultats invalides si un autre thread modifie. P> P>
Ne serait-il pas aussi sûr de ne pas verrouiller obtenir ()? La seule façon de voir que m_data étant invalide est si M_DATA se trouve être> 32 ou 64 bits et il doit effectuer plusieurs missions pour copier l'objet complet. Est-ce la seule raison pour laquelle? Si m_data était un pointeur, je ne vois aucune raison de verrouiller.
@ ACIDEZOMBIE24: Tout dépend de l'architecture avec laquelle vous travaillez et un groupe d'autres facteurs, l'atomicité des lectures / écritures n'est pas appliquée par la langue. Si type code> est une structure contenant 4 caractères, la lecture ne sera probablement pas atomique. Même s'il s'agit d'une valeur unique 32 bits dans un processeur Intel moderne, on peut être non atomique si les données (dans ce cas objet code>) ne sont pas alignées. Encore une fois, lors de l'écriture de code sans verrouillage, vous devez prendre en compte beaucoup i>.
Pour votre exemple spécifique, je recommanderai un verrouillage de lecture de lecture lien a >
@Niki: Il y a une surcharge sur les serrures en lecture, et il est livré avec son propre ensemble de problèmes. Si la section critique est petite, ou le nombre de lecteurs / lectures n'est pas extrêmement supérieur au nombre d'écritures (comme dans plusieurs commandes de magnitude plus grande), vous pouvez être meilleur avec un mutex ordinaire.
@David Rodríguez Enfin, tout dépend de la fréquence de l'utilisation de la classe, quel est le type et combien de temps il faut pour obtenir () à exécuter. Rwlock est toujours plus lourde, mais peut également être mis en œuvre de manière à devenir lourds lors de la conflit lors de l'écriture. Mais je suis sûr que vous savez beaucoup tout ça. Droit d'outils pour le bon problème.
@Niki: Dans mon expérience personnelle, et cela est complètement biaisé, je n'ai jamais rencontré un cas où Rwlock était la meilleure solution. J'ai eu des cas où c'était mieux, mais après avoir travaillé sur la réduction des tailles de la section critique, le mutex ordinaire a fini par être la meilleure solution. Mesure, votre kilométrage peut varier. Mais j'ai supprimé une juste quantité de Rwlocks dans le codebase que je travaille pour de bonnes raisons. C'est mon expérience personnelle, Rwlocks son i> génial, mais ils ne sont pas que i> génial.
@David Rodríguez Merci d'avoir partagé votre expérience et d'être honnête, je n'utilise presque pas Rwlock dans mon code non plus et que pour l'accès à la base de données construit en interne, où la plupart du temps est nécessaire et étouffait trop à cause des serrures normales. Néanmoins, les «bons outils du bon travail» sont toujours à la règle de suivre, avec «simple est belle»
Je dirais que vous mettriez mal compris le mot clé
mutable code>. Où avez-vous eu cette idée qu'il est destiné à affecter la mise en cache de données?@Jonathan: la mise en cache des données est un usage très courant des membres de données code> mutable. Si vous avez une fonction de membre de const qui effectue une tâche coûteuse et que vous savez que la fonction est appelée fréquemment, une optimisation typique consiste à introduire un élément de données mutable pour mettre en cache les résultats de la tâche coûteuse afin que les appels futurs sur cette fonction de membre soient plus rapides. .
Oui, mais c'est un cas d'utilisation, pas la signification du mot clé.
@Jonathan: L'OP n'a pas dit que c'était la signification du mot clé; Il a dit que c'était l'utilisation principale du mot clé (il serait mieux formulé, peut-être, s'il l'a dit "une de ses principales utilisations est ..." Au lieu de "Son utilisation principale est ...").
Regardez, l'OP est confus. Le mot clé
mutable code> est totalement orthogonal pour enfiler. Vraiment,mutable code> n'a rien de plus à voir avec le filetage queconst code> fait. Toutes les modifications i> aux données partagées entre des threads, quelles que soient si les données sontmutables code> ou non, doivent être synchronisées. James McNellis a souligné un cas possible où le mot clé code> mutable code> dans un programme fileté pourrait conduire à un faux sentiment de sécurité, mais cela justifie à peine d'associer les deux concepts car ce n'est pas comme si leconst < / Code> Le mot-clé (ou quoi que ce soit d'autre en C ++ 03) rend toute Garanties i> sur la sécurité thread-sécurité.@Chals Salvia: J'ai clairement dit que les données seraient modifiées et doivent être synchronisées. Theres aucune confusion sur ma part
@ acidzombie24: ... mais vous avez impliqué que
const code> est lié à la multithreading que ce n'est pas le cas. Il n'est pas sûr d'appeler une méthodeconst code> dans un environnement multithreadé sans serrures si un autre thread peut appeler une méthode non code> const code> sur le même objet. De ce point de vue,mutable code> est aussi non liée à multithreading queconst code> est. D'autre part, il est considéré comme prudent pour appeler des méthodes qui ne modifient pas l'objet de plusieurs threads (à condition qu'il existe une garantie selon laquelle aucun autre thread ne modifie l'objet), mais ce n'est pas la même chose que d'appeler unConst code> La méthode est sûre.@David Rodríguez - Dribesas: Oui Exactement. Mais beaucoup assumeraient quand il est constant que cela ne modifierait pas la classe (ou du moins de manière non sûre). Ainsi, mon point, est-il «mauvais» d'utiliser le mot clé mutable. Je voudrais simplement écrire la classe pour ne pas l'utiliser afin d'obtenir une meilleure performance. Je demande vraiment que s'il y a un cas où il serait logique d'utiliser le mot clé mutable, car dans la plupart des cas, vous éviteriez la possibilité de modifier les données si possible.
@ acidzombie24: lors de l'écriture de code multithreadisé, plus qu'avec tout autre type de programme, le conseil serait le faire droit i> alors faites-le rapide i> seulement après la mesure et si nécessaire . Ne pas verrouiller peut être une solution pour un problème particulier, mais dans le cas général, il y a de fortes chances que vous vous sacidiez et que vous avez un problème vraiment difficile à essayer de déboguer le code plus tard. Le code sans verrouille nécessite beaucoup d'attention, et cela signifie en réalité savoir ce que chaque fonction fait réellement ou ne le fait pas.
@ acidzombie24: Avez-vous besoin de verrouiller lorsque vous appelez une méthode
int foo () const code> pour obtenir un résultat constant s'il n'y a pas d'attributs mutables dans l'objet? Cela dépend deFOO code>, dans le meilleur cas, leint code> est uniquement lu à partir de l'objet, et c'est un mot aligné et vous pouvez le tirer sans verrouillage. Dans le pire des cas, le résultat réel est calculé (sans rien modifier) de plus d'un attribut ou n'est pas correctement aligné, aucun de ces cas rendrait le déverrouillage d'appel dangereux. Le problème n'est pas le mot clémutable code>, mais what i> la fonction fait et comment i>En fait, la bibliothèque standard n'utilise jamais aucun membre
mutable code>, car la standard garantit que tous les membres de la fonctionconst code> sont thread-coffre-fort.