examples - struct c++ para que sirve
Llamando a borrar con iterador vs const_iterator (5)
¿Por qué falla la llamada a la función miembro de erase
de un contenedor con un const_iterator
?
Funciona con un iterator
no const.
Con respecto a la constancia, puede pensar en un std::container<T>::const_iterator
como una const T*
.
Ese es el propósito del const_iterator. Los usas cuando los elementos a los que se accede a través de él no deben modificarse.
Esto no se compila porque container::iterator
container::const_iterator
y container::const_iterator
son dos tipos distintos y la única versión (un argumento) de borrado es: iterator erase(iterator);
No aceptar un const_iterator
puede verse como un defecto en el estándar de idioma: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2350.pdf
No hay ninguna razón particular para esta restricción. El iterador solo se usa para indicar una posición en el contenedor (modificable), y ni en el caso de insert
o erase
se modifica el "pointee" del iterador (en caso de erase
, simplemente desaparece conceptualmente, lo que es una normalidad). Lo que hay que hacer para los objetos const).
El estándar actual indica una confusión entre "constancia de iterador y constancia de contenedor" (como lo hacen otras respuestas aquí), y parece que const_iterator
podría ser aceptable para erase
en C ++ 0x.
Como solución alternativa, puede obtener válidamente un iterator
de un const_iterator
porque el contenedor debe ser mutable en primer lugar.
La siguiente función solo es compilable para los iteradores de acceso aleatorio, ya que puede ser un poco demasiado lento para hacer esto con otros tipos de iteradores.
#include <vector>
template <class Container>
typename Container::iterator to_mutable_iterator(Container& c, typename Container::const_iterator it)
{
return c.begin() + (it - c.begin());
}
int main()
{
int arr[] = {1, 5, 2, 5, 3, 4, 5, 1};
std::vector<int> vec(arr, arr + sizeof(arr) / sizeof(*arr));
for (std::vector<int>::const_iterator it = vec.begin(); it != vec.end(); ) {
//if (*it = 5) { //const_iterator prevents this error
if (*it == 5) {
it = vec.erase(to_mutable_iterator(vec, it));
}
else {
++it;
}
}
}
Sin embargo, podría ser mejor reestructurar el código para que no necesite un const_iterator
en primer lugar. En este caso, sería mejor usar el algoritmo std::remove
. Si necesita realizar más trabajos de no mutación antes de borrar, puede extraerlo en un método separado, etc.
Solo quiero enfatizar en la corrección general de las respuestas / comentarios publicados por UncleBens, David Rodriguez e Ise Westeria.
Independientemente de los comportamientos de los compiladores actuales (o anteriores) anteriores a C ++ 11, la corrección constante de const_iterator (debería) se detiene inmediatamente en el sentido de que semánticamente es igual a const T * (o T * const); tenga en cuenta que T en sí puede ser un tipo de const de su propio! - por lo que efectivamente impide que el código modifique el objeto referenciado en el contenedor.
Sin embargo, como es perfectamente legal ''borrar'' un puntero de const en C ++ (¡pruébelo, funciona!), Debería ser (y el comportamiento ha sido corregido en C ++ 11) también legal para ''borrar'' una const iterador de un contenedor, siempre que el contenedor en sí no sea constante.
Parece que Visual Studio 2010 ya se está comportando correctamente al tener ''borrar'' aceptando const_iterator, lo que, por supuesto, me causó algunos dolores de cabeza para detectar algún otro error, lo que me llevó a esta publicación, que finalmente aclaró el comportamiento correcto de "borrar const_iterator" exactitud.
Un tipo const_iterator
no se puede utilizar para modificar el valor de un elemento o el contenedor.