79 votes

C++ STL mise à jour du jeu est fastidieux: je ne peux pas changer un élément dans la place

Je trouve l'opération de mise à jour sur le plateau fastidieux car il n'y a pas une telle API sur cppreference. Donc, ce que je fais qqch comme ceci:

//find element in set by iterator
Element copy = *iterator;
... // update member value on copy, varies
Set.erase(iterator);
Set.insert(copy);

Fondamentalement, l'itérateur de retour en Jeu est un const_iterator et vous ne pouvez pas modifier sa valeur directement.

Est-il une meilleure façon de le faire? Ou peut-être que je devrais remplacer fixé par la création de mon propre (qui je ne sais pas exactement comment ça fonctionne..)

Merci!

82voto

Terry Mahaffey Points 7368

jeu de const retourne itérateurs (que dit la norme set::iterator est const, et que set::const_iterator et set::iterator peut en fait être du même type - voir article 23.2.4/6 dans n3000.pdf), car il est d'un ordre de conteneurs. Si il est revenu régulier d'un itérateur, vous seriez autorisé à modifier les éléments de la valeur sous le récipient, susceptible de modifier la commande.

Votre solution est la idiomatiques de modifier des éléments dans un ensemble.

32voto

Matthieu M. Points 101624

Il y a 2 façons de le faire, dans le cas simple:

  • Vous pouvez utiliser mutable sur la variable qui ne font pas partie de la clé
  • Vous pouvez diviser votre classe en Key Value paire (et utiliser un std::map)

Maintenant, la question est pour le cas délicat: ce qui se passe quand la mise à jour modifie en fait la key de la partie de l'objet ? Votre approche fonctionne, même si j'avoue que c'est fastidieux.

9voto

avakar Points 20031

Mise à jour: Même si ce qui suit est vrai que, désormais, le comportement est considéré comme un défaut et sera modifié dans la prochaine version de la norme. Comment très triste.


Il y a plusieurs points qui font que votre question plutôt déroutant.

  1. Les fonctions peuvent renvoyer des valeurs, les classes peut pas. std::set est une classe, et donc ne retourne rien.
  2. Si vous pouvez appeler s.erase(iter), alors iter n'est pas un const_iterator. erase requiert un non-const itérateur.
  3. Toutes les fonctions de membre de l' std::set qui retourne un itérateur de retour d'un non-const itérateur tant que le jeu est non-const ainsi.

Vous êtes autorisé à modifier la valeur d'un élément d'un ensemble aussi longtemps que la mise à jour ne change pas l'ordre des éléments. Le code suivant compile et fonctionne très bien.

#include <set>

int main()
{
    std::set<int> s;
    s.insert(10);
    s.insert(20);

    std::set<int>::iterator iter = s.find(20);

    // OK
    *iter = 30;

    // error, the following changes the order of elements
    // *iter = 0;
}

Si votre mise à jour modifie l'ordre des éléments, alors vous devez effacer et réinsérez-la.

3voto

bitmask Points 11086

J'ai rencontré le même problème en C++11, où, en effet ::std::set<T>::iterator est constante et ne permet donc pas de modifier son contenu, même si nous savons que la transformation ne sera pas affecter l' < invariant. Vous pouvez contourner ce problème en les enveloppant ::std::set en mutable_set type ou d'écrire un wrapper pour le contenu:

  template <typename T>
  struct MutableWrapper {
    mutable T data;
    MutableWrapper(T const& data) : data(data) {}
    MutableWrapper(T&& data) : data(data) {}
    MutableWrapper const& operator=(T const& data) { this->data = data; }
    operator T&() const { return data; }
    T* operator->() const { return &data; }
    friend bool operator<(MutableWrapper const& a, MutableWrapper const& b) {
      return a.data < b.data;
    }   
    friend bool operator==(MutableWrapper const& a, MutableWrapper const& b) {
      return a.data == b.data;
    }   
    friend bool operator!=(MutableWrapper const& a, MutableWrapper const& b) {
      return a.data != b.data;
    }   
  };

Je trouve cela beaucoup plus simple et il fonctionne dans 90% des cas, sans que l'utilisateur s'en rende compte il y a quelque chose entre le jeu et le type réel.

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