web-dev-qa-db-fra.com

Que se passe-t-il si je lis la valeur d'une carte où la clé n'existe pas?

map<string, string> dada;
dada["dummy"] = "papy";
cout << dada["pootoo"];

Je suis perplexe parce que je ne sais pas si c'est considéré comme un comportement indéfini ou non. Comment savoir quand je demande une clé qui n'existe pas?

51
jokoon

Le map::operator[] cherche dans la structure de données une valeur correspondant à la clé donnée et renvoie une référence à celle-ci.

S'il ne parvient pas à en trouver un, il crée de manière transparente un élément construit par défaut pour celui-ci. (Si vous ne souhaitez pas ce comportement, vous pouvez utiliser la fonction map::at à la place.)

Vous pouvez obtenir une liste complète des méthodes de std :: map ici:

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

Voici la documentation de map::operator[] à partir du standard C++ actuel ...

23.4.4.3 Accès aux éléments de la carte

T& operator[](const key_type& x);

  1. Effets: S'il n'y a pas de clé équivalente à x dans la carte, insère value_type (x, T()) dans la carte.

  2. Requiert: key_type doit être CopyConstructible et mapped_type doit être DefaultConstructible.

  3. Renvoie: Une référence au type mappé correspondant à x dans * this.

  4. Complexité: logarithmique.

T& operator[](key_type&& x);

  1. Effets: S'il n'y a pas de clé équivalente à x dans la carte, insère value_type (std :: move (x), T()) dans la carte.

  2. Requiert: mapped_type doit être DefaultConstructible.

  3. Renvoie: Une référence au type mappé correspondant à x dans * this.

  4. Complexité: logarithmique.

63
Andrew Tomazos

Si vous essayez d'accéder à un key value à l'aide de l'opérateur d'indexation [], deux événements peuvent se produire:

  1. La carte contient cette key. Donc, il retournera le key value correspondant.
  2. La carte ne contient pas la key. Dans ce cas, il ajoutera automatiquement une key à la carte avec null value.

La clé "pootoo" n'existe pas dans votre carte. Donc, il va automatiquement ajouter cette key avec value = "" (chaîne vide). Et votre programme imprimera une chaîne vide.

Ici, la taille de la carte augmentera de 1.

Pour rechercher une clé, vous pouvez utiliser map_name.find(), qui retournera map_name.end() si la clé n'existe pas. Et aucun key supplémentaire ne sera ajouté.

Vous pouvez utiliser l'opérateur [] lorsque vous souhaitez définir la valeur d'une clé.

14
Ali Akber

Ce n'est pas un comportement indéfini. Si operator [] ne trouve pas de valeur pour la clé fournie, il en insère une à cette position. 

7
Luchian Grigore

Pour l'opérateur [], si vous essayez d'accéder à une valeur pour une clé inexistante, un nouvel objet de valeur construit par défaut sera placé dans la carte et sa référence renvoyée.

6
Michael Kohne

Le operator[] pour map renvoie une référence non const et vous pouvez l'affecter de la manière que vous avez indiquée sur votre deuxième ligne. Accéder de cette manière créera un élément construit par défaut de type value.

Si vous voulez trouver un élément à trouver, une meilleure solution est

iterator find ( const key_type& x )

(ou l'alternative const) qui retournera un itérateur égal à <map>.end() s'il ne trouve pas la clé ou si vous voulez simplement savoir s'il fait partie de la collection, vous pouvez utiliser

size_type count ( const key_type& x ) const

qui retournera toujours 1 ou 0 pour une carte puisque les clés sont uniques.

2
Component 10

Si l'opérateur [] ne trouve pas de valeur pour la clé fournie, il en insère une à cette position.

Mais vous devriez noter que si vous visitez un not exist key et appelez sa fonction membre, comme mapKV [not_exist_key] .member_fun (), le programme risque de tomber en panne.

Voyons un exemple, testons la classe ci-dessous:

struct MapValue{
    int val;

    MapValue(int i=0){
        cout<<"ctor: "<<i<<endl; val = i;
    }

    ~MapValue(){
        cout<<"dtor: "<<val<<endl;
    }

    friend ostream& operator<<(std::ostream& out, const MapValue& mv){
        cout<<"MapValue: "<<mv.val<<endl;
    }

    string toString(){
        cout<<"MapValue: "<<val<<endl;
    }
};

Code de test:

cout<<"-------create map<int, MapValue>-------"<<endl;

map<int, MapValue> idName{{1, MapValue(1)}, {2, MapValue(2)}};

cout<<"-----cout key[2]-----"<<endl;
cout<<idName[2]<<endl;

cout<<"-----cout key[5]-----"<<endl;
cout<<idName[5]<<endl;

cout<<"------- runs here means, does't crash-------"<<endl;

Sortie comme ci-dessous:

-------create map<int, MapValue>-------
ctor: 1
ctor: 2
dtor: 2
dtor: 1
dtor: 2
dtor: 1
-----cout key[2]-----
MapValue: 2

-----cout key[5]-----
ctor: 0
MapValue: 0

-------runs here means, does't crash-------
dtor: 0
dtor: 2
dtor: 1

Nous pouvons voir que: idName[5] invoque la construction de la carte {5, MapValue(0)} pour l'insérer dans idName.

Mais si, vous appelez la fonction membre par idName[5], alors le programme obtient un crash:

cout<<"-------create map<int, MapValue>-------"<<endl;

map<int, MapValue> idName{{1, MapValue(1)}, {2, MapValue(2)}};


idName[5].toString();  // get crash here.


cout<<"------- runs here means, does't crash-------"<<endl;
1
Jayhello

consultez l’exception out_of_range: http://www.cplusplus.com/reference/stdexcept/out_of_range/

c'est ce que map :: at et map :: operator [] lancera si la clé n'existe pas. Vous pouvez l'attraper de la même manière que l'exemple de vecteur dans le lien.

Vous pouvez également utiliser: http://www.cplusplus.com/reference/map/map/find/

Et vérifier contre la carte :: fin

0
user2346536