web-dev-qa-db-fra.com

L'opérateur std :: unordered_map [] fait-il l'initialisation à zéro pour une clé non existante?

Selon cppreference.com, std::map::operator[] pour une valeur non existante fait une initialisation nulle.

Cependant, le même site ne mentionne pas d'initialisation nulle pour std::unordered_map::operator[] , sauf qu'il a un exemple qui s'appuie sur cela.

Bien sûr, ce n'est qu'un site de référence, pas la norme. Alors, le code ci-dessous est-il correct ou non?

#include <unordered_map>
int main() {
    std::unordered_map<int, int> map;
    return map[42];     // is this guaranteed to return 0?
}
25
hyde

Selon la surcharge dont nous parlons, std::unordered_map::operator[] Équivaut à [unord.map.elem]

T& operator[](const key_type& k)
{
    return try_­emplace(k).first->second;
}

(la surcharge prenant une référence rvalue déplace simplement k dans try_emplace et est par ailleurs identique)

Si un élément existe sous la clé k dans la carte, alors try_emplace Renvoie un itérateur à cet élément et false. Sinon, try_emplace Insère un nouvel élément sous la clé k, et renvoie un itérateur à cela et true[unord.map.modifiers] :

template <class... Args>
pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);

Intéressant pour nous est le cas où il n'y a pas encore d'élément [unord.map.modifiers]/6 :

Sinon, insère un objet de type value_­type Construit avec piecewise_­construct, forward_­as_­Tuple(k), forward_­as_­Tuple(std​::​forward<Args>(args)...)

(la surcharge prenant une rvalue-reference déplace simplement k dans forward_­as_­Tuple et, là encore, est par ailleurs identique)

Puisque value_type Est un pair<const Key, T>[unord.map.overview]/2 , cela nous indique que le nouvel élément de carte sera construit comme suit:

pair<const Key, T>(piecewise_­construct, forward_­as_­Tuple(k), forward_­as_­Tuple(std​::​forward<Args>(args)...));

Puisque args est vide en venant de operator[], Cela revient à notre nouvelle valeur étant construite en tant que membre de pair sans argument [pairs.pair ]/14 qui est une initialisation directe [class.base.init]/7 d'une valeur de type T en utilisant () Comme initialiseur qui se résume à initialisation de la valeur [dcl.init] /17.4 . L'initialisation de la valeur d'un int est une initialisation nulle [dcl.init]/8 . Et l'initialisation zéro d'un int initialise naturellement ce int à 0 [dcl.init]/6 .

Alors oui, votre code est garanti pour retourner 0…

13
Michael Kenzel

Sur le site que vous avez lié, il est écrit:

Lorsque l'allocateur par défaut est utilisé, cela entraîne la construction de la copie à partir de la clé et l'initialisation de la valeur mappée.

Donc, le int est valeur initialisée :

Les effets de l'initialisation de la valeur sont:

[...]

4) sinon, l'objet est initialisé à zéro

C'est pourquoi le résultat est 0.

21
Blaze