2010-09-21 19 views
3

En d'autres termes, lorsque i est un map<K,V>::iterator, effectuez les opérations suivantes fournissent la sémantique attendue (.-À-dire qu'il modifie la carte):Est-ce que map :: iterator donne des valeurs?

*i = make_pair(k, v); 
i->first = k; 
i->second = v; 

?

Mise à jour: (convertible) Les deux premières lignes ne sont pas valides, puisque la valeur de retour de operator* est un pair<const K, V>. Qu'en est-il de la troisième ligne?

En supposant un oui réponse à trois, cela impliquerait que:

  • Soit map<K,V> éléments sont stockés comme pair<K,V> quelque part,
  • Ou il y a une classe proxy intelligent qui map<K,V>::iterator::operator* de retour. Dans ce cas, comment est implémenté operator->?
  • carte
+0

http://www.cplusplus.com/reference/std/utility/make_pair/ - – DumbCoder

+1

@DumbCoder: J'aimerais savoir si '* i' renvoie une * référence * à un objet pair, ou à une paire object, ou certaines classes proxy convertibles en 'pair', mais qui fournit une sémantique lvalue. –

+0

> Débogué et montre un objet paire modélisé, en cours de construction et retourné. – DumbCoder

Répondre

4

J'ai essayé de suivre cette baisse par la norme:

  • Pour map<Key,T> le value_type est pair<const Key,T> par 23.3.1/2

  • La classe carte prend en charge itérateurs bidirectionnelle, par 23.3.1/1

  • itérateur bidirectionnel remplit les conditions pour le transmettre rateurs, par 24.1.4/1

  • Pour un itérateur vers l'avant avec aTvalue_type, expression *a rendements & T (pas de type "convertible en T", comme certains autres itérateurs font) (tableau 74 dans 24,1 .3)

Par conséquent, l'exigence est de renvoyer une référence à la paire, et non un autre type de proxy.

+0

Génial. Cela limite quelque peu la mise en œuvre, intéressante. Je vous remercie ! –

3

est presque comme un ensemble de paires. Oui, son itérateur est probablement implémenté comme un pointeur vers un nœud avec un pair<const K,V>. Cependant votre code est valide, car les valeurs sont en fait de type pair<const K, V> vous pouvez donc pas céder à first. * 0 renvoie pair<const K, V>& ou un proxy qui se comporte comme ce type (impossible de trouver une sauvegarde de la dernière revendication de la norme). Vous pouvez implémenter ces proxys en surchargeant operator ->.

+0

Non, lvalue/rvalue est une distinction de * expressions *, pas d'objets. Voir [ISO03, 3.10 basic.lval §1]. Il peut y avoir plusieurs valeurs et rvalues ​​indiquant le même objet. – fredoverflow

+0

En outre, je ne vois pas le problème avec la formulation de ma question. Je pense que je sais ce qu'est une lvalue. –

+0

Désolé, mal lu la question (lire 'est' au lieu de 'rendements'). – ybungalobill

1

Tout d'abord, l'opérateur technique * unaire est évaluée à un lvalue dans ce cas. Cependant, le terme lvalue en C désigne essentiellement quelque chose qui a un emplacement (adresse) en mémoire (mémoire). En terminologie C++, les fonctions paires sont lvalues ​​. Donc, encore une fois, dans votre exemple ci-dessus l'unaire * donner une lvalue. Vous pouvez prendre l'adresse de ce lvalue, si vous souhaitez le faire, à savoir que vous pouvez évaluer &*i, &i->first et &i->second (en supposant que le unaire intégré &). Deuxièmement, puisque votre exemple original implique l'affectation, vous devez parler en fait de lvalues ​​modifiables. Vous voyez, la propriété d'être lvalue par lui-même a très peu à voir avec être assignable. Pour utiliser l'opérateur d'affectation intégré, vous avez besoin d'un modifiable lvalue. Ce que vous obtenez d'un itérateur déréférencé est value_type de std::map. C'est une paire avec un premier membre const-qualifié, comme vous le savez déjà. Cela rend automatiquement le premier membre non modifiable, ce qui rend la paire entière non modifiable par l'opérateur d'affectation intégré. Le deuxième membre de la paire est modifiable, comme vous l'avez déjà observé.

Ainsi, une fois encore, l'opérateur de déréférencement dans ce cas retourne une lvalue. Cette lvalue est non modifiable dans son ensemble, et son premier membre est également non modifiable. Son deuxième membre est une lvalue modifiable. Comme pour votre hypothèse sur la façon dont les éléments de std::map sont stockés, je dirais que dans une implémentation typique, ils seront stockés en tant qu'objets pair<const K, V>, c'est-à-dire exactement ce que l'opérateur de déréférencement évalue.Normalement, la carte n'a pas besoin de modifier la partie clé de la paire après son initialisation, donc elle ne devrait pas rencontrer de problèmes avec le fait que le premier membre de la paire est const-qualifié.

+0

Merci pour le nitpicking, mais il ne répond pas à la question. Est-ce que l'assignation au second membre change la carte? –

+0

@Alex: La réponse est oui. Mais pourquoi ne l'as-tu pas essayé par toi-même? – fredoverflow

+0

@Alexandre C .: Je ne vois pas la question "ça change la carte" dans le PO, mais la réponse est oui, ça change la carte. – AnT

1
map<K,V>::iterator i = my_map.begin(); 

*i = make_pair(k, v); // invalid, you cannot assign to a pair<const K,V>& 
i->first = k; // invalid cannot write to const 
i->second = v; // valid 
+0

Supposons que 'i' est valide alors. –

+0

@Alexandre: Paul a raison. Vous ne pouvez pas écrire dans un 'std :: map :: value_type', peu importe si l'itérateur est valide. La raison en est que 'std :: map :: value_type' se développe en' std :: pair '(notez le' const'), qui, même s'il s'agit d'une lvalue, ne peut toujours pas être écrit. «+ 1» de moi pour contrer le vote inutile. – sbi

+0

Paul, j'ai pris la liberté d'éditer ta réponse pour la rendre plus claire. J'espère que cela ne vous dérange pas. – sbi