ProgrammationDéveloppeur C++ Middle

Qu'est-ce que l'opérateur [] en C++ ? Comment surcharger correctement cet opérateur pour des conteneurs personnalisés ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

L'opérateur d'accès par index operator[] est un opérateur surchargé en C++ permettant de fournir une syntaxe d'indexation sur des objets de conteneurs personnalisés (par exemple, similaire aux tableaux).

Historique de la question :

Dans le langage C, puis en C++, l'opérateur [] permettait d'accéder rapidement et facilement aux éléments d'un tableau par index. Cependant, avec l'essor des classes de conteneurs, il est devenu nécessaire de transférer cette même syntaxe aux types de données personnalisés.

Problème :

La conception correcte des opérateurs d'accès par index soulève des questions de constance, de sécurité contre les débordements (out-of-bounds), de choix de valeur de retour et de garantie de validité de la référence ou du pointeur.

Solution :

En C++, il est possible de surcharger operator[] pour des classes, permettant ainsi un accès aux éléments par index et d'implémenter un "comportement similaire à un tableau". Il faut implémenter les deux versions de l'opérateur - ordinaire (pour les objets non constants) et constante (pour les objets constants).

Exemple de code :

class MyArray { int data[10]; public: int& operator[](size_t index) { return data[index]; } const int& operator[](size_t index) const { return data[index]; } }; MyArray arr; arr[3] = 42; // OK const MyArray& const_arr = arr; int val = const_arr[3]; // OK

Caractéristiques clés :

  • Implémentez toujours les versions const et non-const de l'opérateur pour un fonctionnement correct avec des objets constants
  • Ne réalise pas de vérifications de débordement (contrairement à .at() dans les conteneurs standard)
  • Il est important de choisir le type de retour (référence, pointeur, valeur) de manière consciente

Questions pièges.

Le retour d'une référence depuis operator[] est-il obligatoire ?

Non - mais si vous retournez une valeur, la syntaxe arr[i] = x; ne fonctionnera pas (vous allez copier au lieu d'assigner). Pour maintenir la sémantique habituelle du conteneur, on retourne généralement une référence. Si vous retournez une valeur, l'écriture d'un élément ne fonctionnera pas :

int operator[](size_t idx); // arr[2] = 10; ne compilera pas

operator[] doit-il vérifier les limites ?

La norme ne l'exige pas. L'opérateur classique operator[] (comme dans std::vector) NE fait pas de telles vérifications. Pour des vérifications, les conteneurs standards introduisent une méthode distincte .at(), qui lance une exception en cas de dépassement de bord.

operator[] peut-il être une méthode constante ?

Non - si vous retournez une référence non constante. Cependant, il est nécessaire de surcharger operator[] à la fois pour les objets constants et non constants, afin que le conteneur fonctionne de manière intuitive et sécurisée.

Erreurs typiques et anti-modèles

  • Ne pas implémenter la version constante de l'opérateur (ce qui empêche d'accéder aux éléments via une référence const)
  • Retourner une valeur et non une référence, brisant ainsi la sémantique de l'assignation
  • Laisser des éléments non initialisés dans le conteneur

Exemple de la vie réelle

Cas négatif

Un jeune développeur a uniquement implémenté la version non constante de operator[], retournant par valeur. En conséquence, le conteneur ne pouvait pas être accédé via une référence const, et toute tentative d'écriture agissait de manière étrange – les valeurs n'étaient pas conservées.

Avantages :

  • Compile tant que vous utilisez uniquement des objets non constants

Inconvénients :

  • La sémantique attendue de C++ est violée
  • La const-correctness ne fonctionne pas, et les algorithmes standards ne sont pas pris en charge

Cas positif

Dans le conteneur MyArray, les deux versions de operator[] ont été implémentées, avec un retour correct de références. Si nécessaire, la méthode at() avec vérification des limites a été ajoutée.

Avantages :

  • Le conteneur se comporte "selon les standards"
  • Tous les modes sont supportés (const, non constant, lecture, écriture)

Inconvénients :

  • L'utilisation de operator[] peut toujours entraîner une erreur de débordement
  • La complexité de la classe augmente légèrement