95 votes

Pourquoi l'opérateur [] n'est-il pas constant pour les cartes STL ?

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, puisque l'opérateur [] est non-const.

C'est regrettable, car la syntaxe [] semble 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 non-const ?

5 votes

Qu'est-ce qui devrait operator[] le rendement dans le cas où l'élément donné n'existe pas ?

5 votes

@Frerich Raabe : La même chose que la fonction membre at : throw std::out_of_range

95voto

Alan Points 3489

Pour std::map y std::unordered_map , operator[] insère la valeur de l'index dans le conteneur si elle n'existait pas auparavant. Ce n'est pas très 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 un fichier de type const instance du conteneur.

http://en.cppreference.com/w/cpp/container/map/operator_at

3 votes

std::set n'a pas operator[] .

2 votes

C'est la bonne réponse, mais une version const pourrait faire la même chose que le membre "at". C'est-à-dire lancer un std::out_of_range...

1 votes

Lorsqu'il est utilisé pour lire une valeur, il n'y a pas de valeur par défaut à fournir. std::vector a un opérateur de lecture [] c'est-à-dire const . map devrait faire de même.

57voto

Deqing Points 2178

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;
}

5 votes

Si map ont des constantes et des non-constantes at() pourquoi ne pas faire de même pour les operator[] ? avec la version const qui n'insère rien mais plutôt qui jette ? (Ou renvoyer un optionnel, lorsque std::optional sera intégré à la norme).

0 votes

@einpoklum L'intérêt de la correction des constantes est principalement la vérification statique à la compilation. Je préfère que le compilateur se plaigne plutôt que de lancer une exception parce que je n'ai pas utilisé les objets const correctement.

0 votes

@einpoklum Très en retard, mais pour les autres lecteurs : avoir deux surcharges faisant des choses aussi différentes serait terrible. La seule raison at est en deux versions, parce qu'il fait un return *this; et la seule différence entre les surcharges est l'option const -de la référence renvoyée. Les effets réels des deux at sont exactement les mêmes (c'est-à-dire sans effet).

27voto

Loki Astari Points 116129

Note pour les nouveaux lecteurs.
La question initiale portait sur les conteneurs STL (et non sur la std::map).

Il convient de noter qu'il existe une version const de l'opérateur [] sur la plupart des conteneurs.
C'est juste que std::map et std::set n'ont pas de version const et ceci est un 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 

De même, dans votre deuxième exemple, vous devriez 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
    }
}

2 votes

std::set n'a pas operator[] du tout.

2voto

Satbir Points 2942

Puisque operator[] 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 operator[] est extrêmement simple : m[k] est équivalent à (*((m.insert(value_type(k, data_type()))).first)).second. Strictement parlant, cette fonction membre n'est pas nécessaire : elle n'existe que pour des raisons de commodité.

-2voto

Anthony Cramp Points 1665

Si vous déclarez votre variable membre std::map comme étant mutable

mutable std::map<...> m_map;

vous pouvez utiliser les fonctions membres non-const de std::map dans vos fonctions membres const.

16 votes

C'est une idée terrible, cependant.

7 votes

L'API de votre classe repose si vous faites cela. La fonction prétend qu'elle est const -- ce qui signifie qu'elle ne modifiera aucune variable membre -- mais en réalité elle pourrait modifier le membre de données m_map.

2 votes

mutable peut être utilisé pour des membres comme std::mutex les caches et les aides au débogage. Si la carte doit être utilisée comme un cache pour accélérer un processus très coûteux, elle peut être utilisée comme un outil d'aide au débogage. const fonction "getter", alors mutable est acceptable. Vous devez être prudent, mais ce n'est pas une idée terrible en soi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X