Quelle est la différence entre const iterator et non-const iterator dans le C++ STL?

Quelle est la différence entre un const_iterator et un iterator et où utiliseriez-vous l'un par rapport à l'autre?

98
demandé sur WeZZard 2008-11-21 20:36:25

7 réponses

const_iterator s ne vous permettent pas de changer les valeurs qu'ils pointent à, régulier iterator s font.

comme avec toutes les choses en C++, toujours préférer const , à moins qu'il y ait une bonne raison d'utiliser des itérateurs réguliers (i.e. vous voulez utiliser le fait qu'ils ne sont pas const pour changer la valeur pointée).

91
répondu Dominic Rodger 2008-11-21 17:39:25

ils devraient être assez explicites. Si iterator pointe vers un élément de type T, alors const_iterator pointe vers un élément de type 'const T'.

c'est essentiellement équivalent aux types de pointeurs:

T* // A non-const iterator to a non-const element. Corresponds to std::vector<T>::iterator
T* const // A const iterator to a non-const element. Corresponds to const std::vector<T>::iterator
const T* // A non-const iterator to a const element. Corresponds to std::vector<T>::const_iterator

un itérateur de constellation indique toujours le même élément, de sorte que l'itérateur lui-même est const. Mais l'élément qu'il pointe n'a pas à être const, donc l'élément qu'il pointe peut être changé. Un const_iterator est un itérateur qui pointe vers un élément const, alors que l'itérateur lui-même peut être mis à jour (incrémenté ou décrémenté, par exemple), l'élément qu'il pointe ne peut pas être modifié.

30
répondu jalf 2008-11-21 17:51:09

malheureusement, beaucoup de méthodes pour les conteneurs STL prend iterators au lieu de consta_iterators comme paramètres. Donc, si vous avez un const_iterator , vous ne pouvez pas dire "insérer un élément avant l'élément que cet itérateur pointe à" (dire une telle chose n'est pas conceptuellement une violation de const, à mon avis). Si vous voulez faire cela de toute façon, vous devez le convertir en un itérateur non-const en utilisant std::advance() ou boost::next() . Par exemple. boost::next(conteneur.begin(), std::distance(récipient.begin (), the_const_iterator_we_want_to_unconst)) . Si conteneur est un std::list , alors le temps d'exécution de cet appel sera O(n) .

ainsi la règle universelle pour ajouter const partout où il est "logique" de le faire, est moins universelle quand il s'agit de Des conteneurs STL.

toutefois, les conteneurs boost prennent des consta_iterators (p. ex. boost:: unordered_map:: erase()). Ainsi, lorsque vous utilisez des boost containers, vous pouvez être "agressif". En passant, quelqu'un sait si ou lorsque les conteneurs STL sera corrigé?

6
répondu Magnus Andermo 2010-12-18 22:48:07

utilisez const_iterator lorsque vous le pouvez, utilisez iterator lorsque vous n'avez pas d'autre choix.

4
répondu Naveen 2008-11-21 17:51:33

exemples minimaux

non-const itérateurs vous permettent de modifier ce qu'ils pointent à:

std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();
*it = 1;
assert(v[0] == 1);

Const itérateurs n'est pas:

const std::vector<int> v{0};
std::vector<int>::const_iterator cit = v.begin();
// Compile time error: cannot modify container with const_iterator.
//*cit = 1;

comme indiqué ci-dessus, v.begin() est const surchargé, et renvoie soit iterator ou const_iterator selon la configuration du conteneur variable:

un cas courant où const_iterator apparaît est lorsque this est utilisé à l'intérieur d'une const méthode:

class C {
    public:
        std::vector<int> v;
        void f() const {
            std::vector<int>::const_iterator it = this->v.begin();
        }
        void g(std::vector<int>::const_iterator& it) {}
};

const fait this const, qui fait this->v const.

vous pouvez habituellement oubliez cela avec auto , mais si vous commencez à passer ces itérateurs autour, vous aurez besoin de penser à eux pour les signatures de la méthode.

comme const et non const, vous pouvez convertir facilement de non-const de const, mais pas dans l'autre sens:

std::vector<int> v{0};
std::vector<int>::iterator it = v.begin();

// non-const to const.
std::vector<int>::const_iterator cit = it;

// Compile time error: cannot modify container with const_iterator.
//*cit = 1;

// Compile time error: no conversion from const to no-const.
//it = ci1;

laquelle utiliser: analogue à const int vs int : préférer les convertisseurs lorsque vous pouvez les utiliser (lorsque vous n'avez pas besoin de modifier le conteneur avec pour mieux documenter votre intention de lire sans la modifier.

1

(comme d'autres l'ont dit) const_iterator ne vous permet pas de modifier les éléments sur lesquels il pointe, c'est utile à l'intérieur des méthodes de la classe const. Il vous permet également d'exprimer votre intention.

0
répondu Trey Jackson 2008-11-21 18:42:17

ok Permettez-moi de l'expliquer avec un exemple très simple d'abord sans utiliser itérateur constant considérons que nous avons de collecte des entiers aléatoires de la collection "randomData"

    for(vector<int>::iterator i = randomData.begin() ; i != randomData.end() ; ++i)*i = 0;
for(vector<int>::const_iterator i = randomData.begin() ; i!= randomData.end() ; ++i)cout << *i;

comme on peut le voir pour écrire/éditer des données à l'intérieur de la collecte iterator normal est utilisé, mais pour la lecture but iterator constant a été utilisé . Si vous essayez d'utiliser iterator constant en premier pour boucle, vous obtiendrez erreur . En règle générale, utilisez constant iterator pour lire les données à l'intérieur de la collection .

0
répondu Mr Coder 2011-01-17 06:32:18