Exemple artificiel, pour le bien de la question:
void MyClass::MyFunction( int x ) const
{
std::cout << m_map[x] << std::endl
}
Cela ne compilera pas, car l'opérateur [] est non-const.
C'est dommage, car la syntaxe [] a l'air très propre. Au lieu de cela, je dois faire quelque chose comme ceci:
void MyClass::MyFunction( int x ) const
{
MyMap iter = m_map.find(x);
std::cout << iter->second << std::endl
}
Cela m'a toujours dérangé. Pourquoi l'opérateur [] est-il non-const?
operator[]
rapporter au cas où l'élément donné n'existe pas?Réponses:
Pour
std::map
etstd::unordered_map
,operator[]
insérera la valeur d'index dans le conteneur si elle n'existait pas auparavant. C'est un peu peu intuitif, mais c'est comme ça.Puisqu'il doit être autorisé à échouer et à insérer une valeur par défaut, l'opérateur ne peut pas être utilisé sur une
const
instance du conteneur.http://en.cppreference.com/w/cpp/container/map/operator_at
la source
std::set
n'a pasoperator[]
.std::vector
a un opérateur de lecture[]
qui estconst
.map
devrait faire de même.Maintenant qu'avec C ++ 11, vous pouvez avoir une version plus propre en utilisant at ()
void MyClass::MyFunction( int x ) const { std::cout << m_map.at(x) << std::endl; }
la source
map
ont const et non-constat()
s - pourquoi pas la même chose aussi pouroperator[]
? avec la version const n'insérant rien mais plutôt jetant? (Ou renvoyer un optionnel, lorsque std :: optional en fait le standard)at
existe en deux versions, c'est parce qu'il fait unreturn *this;
, et la seule différence entre les surcharges est laconst
-ness de la référence renvoyée. Les effets réels des deuxat
s sont exactement les mêmes (c'est-à-dire aucun effet).Remarque pour les nouveaux lecteurs.
La question d'origine concernait les conteneurs STL (pas spécifiquement le std :: map)
Il faut noter qu'il existe une version const de operator [] sur la plupart des conteneurs.
C'est juste que std :: map et std :: set n'ont pas de version const et c'est le résultat de la structure sous-jacente qui les implémente.
De std :: vector
reference operator[](size_type n) const_reference operator[](size_type n) const
Pour votre deuxième exemple, vous devez également vérifier si l'élément n'a pas été trouvé.
void MyClass::MyFunction( int x ) const { MyMap iter = m_map.find(x); if (iter != m_map.end()) { std::cout << iter->second << std::endl } }
la source
std::set
n'a pasoperator[]
du tout.Puisque l'opérateur [] peut insérer un nouvel élément dans le conteneur, il ne peut pas s'agir d'une fonction membre const. Notez que la définition de l'opérateur [] est extrêmement simple: m [k] équivaut à (* ((m.insert (value_type (k, data_type ()))). First)). Second. À proprement parler, cette fonction membre n'est pas nécessaire: elle n'existe que par commodité
la source
Un opérateur d'index ne doit être const que pour un conteneur en lecture seule (qui n'existe pas vraiment en STL en soi).
Les opérateurs d'index ne sont pas seulement utilisés pour regarder des valeurs.
la source
const
, une autre nonconst
- comme par exemplestd::vector
.Si vous déclarez que votre variable membre std :: map est mutable
mutable std::map<...> m_map;
vous pouvez utiliser les fonctions membres non const de std :: map dans vos fonctions membres const.
la source
mutable
peut être utilisé pour les membres commestd::mutex
, les caches et les aides au débogage. Si la carte doit être utilisée comme cache pour accélérer uneconst
fonction "getter" très coûteuse , alorsmutable
c'est acceptable. Vous devez être prudent, mais ce n'est pas une mauvaise idée en soi.