2008-11-21 21 views

Respuesta

85

const_iterator s no le permiten cambiar los valores que señalan, iterator s normal.

Como con todas las cosas en C++, siempre prefiera const, a menos que haya una buena razón para usar iteradores regulares (es decir, desea utilizar el hecho de que no son const para cambiar el valor apuntado).

+4

En un mundo perfecto ese sería el caso. Pero con C++ const es solo tan buena como la persona que escribió el código :( – JaredPar

+0

mutable existe por una muy buena razón. Se usa raramente, y al buscar en Google Code Search, parece haber un porcentaje razonable de usos válidos. es una herramienta de optimización muy poderosa, y no es como eliminarla, mejoraría la corrección de la const (* tospointerscoughandcoughreferencescough *) – coppro

+1

Más como un poderoso truco. De todas las instancias que he visto del uso de la palabra clave 'mutable', todo menos uno era un indicador preciso de que el código estaba mal escrito y se necesitaba modificar como un truco para evitar los defectos. –

28

Deberían ser casi autoexplicativas. Si el iterador apunta a un elemento de tipo T, entonces const_iterator apunta a un elemento de tipo 'const T'.

es básicamente equivalente a los tipos de puntero:

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 iterador const siempre apunta al mismo elemento, por lo que el iterador sí es const. Pero el elemento al que apunta no tiene que ser const, por lo que el elemento al que apunta se puede cambiar. Un const_iterator es un iterador que apunta a un elemento const, por lo que aunque el iterador mismo se puede actualizar (aumentar o disminuir, por ejemplo), el elemento al que apunta no se puede cambiar.

+1

"Un iterador constante siempre apunta al mismo elemento," Esto es incorrecto. –

+1

¿Cómo es eso? Tenga en cuenta el guion bajo que falta. Estoy contrastando una variable de tipo const std :: vector :: iterator con std :: vector :: const_iterator. En el primer caso, el iterador en sí es const, por lo que no se puede modificar, pero el elemento al que hace referencia se puede modificar libremente. – jalf

+3

Ah, ya veo. Sí, me perdí el guión bajo que faltaba. –

4

Uso const_iterator cada vez que pueda, utilice iterador cuando no tiene otra opción.

0

(como han dicho otros) const_iterator no le permite modificar los elementos a los que apunta, esto es útil dentro de los métodos de clase const. También le permite expresar su intención.

6

Unfortunaty, muchos de los métodos para los contenedores STL toma iteradores en lugar de const_iterators como parámetros. Entonces, si tiene const_iterator, no puede decir "inserte un elemento antes del elemento al que apunta este iterador" (diciendo que tal cosa no es conceptualmente una violación const, en mi opinión). Si desea hacer eso de todos modos, debe convertirlo a un iterador no const utilizando std :: advance() o boost :: next(). P.ej. boost :: next (container.begin(), std :: distance (container.begin(), the_const_iterator_we_want_to_unconst)). Si contenedor es std :: list, entonces el tiempo de ejecución para esa llamada será O (n).

Por lo tanto, la regla universal para agregar const donde sea que sea "lógico" hacerlo, es menos universal cuando se trata de contenedores STL.

Sin embargo, los contenedores de impulso toman const_iterators (por ejemplo, boost :: unordered_map :: erase()). Entonces, cuando usas contenedores de impulso puedes ser "const agresivo". Por cierto, ¿alguien sabe si los contenedores de STL serán reparados o cuándo?

+0

Puede ser una cuestión de opinión. En el caso de 'vector' y' deque', insertar un elemento invalida todos los iteradores existentes, lo cual no es muy 'const'. Pero veo tu punto. Tales operaciones están protegidas por el contenedor 'const'-ness, no por los iteradores. Y me pregunto por qué no hay una función de conversión de iterador const-to-nonconst en la interfaz de contenedor estándar. – Potatoswatter

+0

Usted es correcto Potatoswatter, soy categórico, es una cuestión de opinión para los contenedores de acceso aleatorio y ** container.begin() + (the_const_iterator_we_want_to_unconst - container.begin()) ** es ** O (1) * * de todas formas. También me pregunto por qué no hay una función de conversión para los contenedores de acceso no aleatorio, pero tal vez haya una buena razón. ¿Sabes si hay alguna razón por la cual las funciones para los contenedores de acceso no aleatorio no tengan ** const_iterators **? –

0

bien Voy a explicar con ejemplo muy simple primero sin utilizar iterador constante consideramos que tenemos colección de recogida de números enteros aleatorios "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; 

Como puede verse por los datos de edición/escritura dentro de la colección iterador normales se usa, pero para fines de lectura se ha utilizado un iterador constante. Si intentas usar el iterador constante en el primer ciclo, obtendrás un error. Como regla general, usa el iterador constante para leer datos dentro de la colección.

0

ejemplos mínimos

iteradores no constante permiten modificar lo que apuntan a: iteradores

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

Const no:

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; 

Como puede observarse, v.begin() es const sobrecargado y devuelve iterator o const_iterator dependiendo de la const-dad de la variable contenedor:

Un caso común donde const_iterator aparece es cuando this se utiliza dentro de un método const:

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 hace this const, wh ich hace this->v const.

Por lo general, puede olvidarse de ello con auto, pero si comienza a pasar esos iteradores, tendrá que pensar en ellos para las firmas de método.

Al igual que const y no constante, puede convertir fácilmente de no-const a const, pero no a la inversa:

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; 

cuál usar: análogo a const int vs int: prefiera const iteradores siempre que pueda usarlos (cuando no necesite modificar el contenedor con ellos), para documentar mejor su intención de leer sin modificar.

Cuestiones relacionadas