c++ - que - ¿Debo preferir iteradores sobre const_iterators?
iteradores c++ (6)
Alguien aquí recientemente mencionó el artículo de Scott Meyers que dice:
- Prefiere
iterators
sobreconst_iterators
( enlace pdf ).
Alguien más estaba comentando que el artículo probablemente está desactualizado. Me pregunto cuáles son tus opiniones?
Aquí está el mío: uno de los puntos principales del artículo es que no se puede borrar o insertar en un const_iterator
, pero creo que es gracioso usar eso como un argumento en contra de const_iterators
. Pensé en el punto const_iterators
de los const_iterators
que no modificas el rango en absoluto, ni los elementos en sí mismos sustituyendo sus valores ni el rango insertando o borrando. ¿O me estoy perdiendo algo?
C ++ 98
Creo que hay que tener en cuenta que la declaración de Meyers se refiere a c ++ 98. Es difícil decirlo hoy, pero si recuerdo bien.
- simplemente no fue fácil obtener un const_iterator para un contenedor no const en absoluto
- si obtuviera un const_iterator, difícilmente podría haberlo utilizado ya que se esperaba que la mayoría de los argumentos de posición para las funciones de miembro de contenedor fueran iteradores y no const_iterators
p.ej
std::vector<int> container;
habría requerido
static_cast<std::vector<int>::const_iterator>(container.begin())
para obtener un const_iterator, que habría inflado considerablemente un simple .find e incluso si hubiera obtenido el resultado, después de
std::vector<int>::const_iterator i = std::find(static_cast<std::vector<int>::const_iterator>(container.begin()), static_cast<std::vector<int>::const_iterator>(container.end()),42);
no habría habido ninguna manera de usar su std :: vector :: const_iterator para la inserción en el vector o cualquier otra función miembro que esperara iteradores para una posición. Y no había manera de obtener un iterador de un constador iterador. No hay manera de lanzar (existe?) Para eso.
Debido a que const iterator no significa que el contenedor no se pueda cambiar, sino que el elemento apuntado no se puede cambiar (constiter es el equivalente de puntero a const) que en realidad era una gran pila de basura para tratar en tales casos .
Hoy es todo lo contrario.
Los iteradores son fáciles de obtener usando cbegin, etc., incluso para los contenedores que no son const y todas las funciones miembro (?) que toman posiciones tienen constadores como sus argumentos, por lo que no es necesario realizar ninguna conversión.
std::vector<int> container;
auto i = std::find(container.cbegin(), container.cend(), 42);
container.insert(i, 43);
Entonces, ¿qué fue una vez
Prefiere iteradores sobre const_iterators
hoy realmente debería ser
Prefiero const_iterators sobre iteradores
ya que el primero es simplemente un artefacto de déficits históricos de implementación.
Al leer ese enlace, Meyers parece estar diciendo fundamentalmente que los interator son mejores que los const_interator porque no se pueden hacer cambios a través de un const_iterator.
Pero si eso es lo que está diciendo, entonces Meyers está, de hecho, equivocado. Esta es precisamente la razón por la que const_iterator''s es mejor que iterator cuando eso es lo que quiere expresar.
Aquí hay una forma ligeramente diferente de verlo. Const_iterator
casi nunca tiene sentido cuando lo pasa como un puntero a una colección específica y también pasa la colección. El Sr. Meyer declaró específicamente que const_iterator
no se puede usar con la mayoría de las funciones miembro de una instancia de colección. En ese caso, necesitará un iterator
simple. Sin embargo, si no tiene un identificador de la colección, la única diferencia entre los dos es que puede modificar lo que apunta un iterator
y no puede modificar el objeto al que hace referencia un const_iterator
.
Entonces ... desea usar iterator
cada vez que pase una colección y posición en la colección a un algoritmo. Básicamente, firmas como:
void some_operation(std::vector<int>& vec, std::vector::const_iterator pos);
no tiene mucho sentido La declaración implícita es que some_operation
es libre de modificar la colección subyacente, pero no está permitido modificar las referencias de posición. Eso no tiene mucho sentido. Si realmente quieres esto, entonces pos
debe ser un desplazamiento en lugar de un iterador.
Por otro lado, la mayoría de los algoritmos en la STL se basan en rangos especificados por un par de iteradores. La colección en sí nunca se pasa, por lo que la diferencia entre iterator
y const_iterator
es si el valor de la colección se puede modificar a través del iterador o no. Sin una referencia a la colección, la separación es bastante clara.
Esperemos que las cosas queden tan claras como el barro;)
Estoy totalmente de acuerdo contigo. Creo que la respuesta es simple: use const_iterators donde los valores const son los correctos y viceversa. Me parece que los que están en contra de const_iterators deben estar en contra de const en general ...
Generalmente prefiero constness, pero recientemente encontré un enigma con const_iterators que ha confundido mi filosofía de "siempre es posible usar const const:"
MyList::const_iterator find( const MyList & list, int identifier )
{
// do some stuff to find identifier
return retConstItor;
}
Ya que pasar una referencia a la lista de const requiere que solo use constadores de it, ahora si uso el hallazgo, no puedo hacer nada con el resultado, pero mírelo aunque todo lo que quería hacer era expresar que encontrar no cambiaría la lista que estaba aprobada en.
Quizás me pregunte, entonces, si el consejo de Scott Mayers tiene que ver con cuestiones como esta, en las que resulta imposible escapar de la constancia. Por lo que entiendo, no puede (confiablemente) des-const constatar con un simple cast debido a algunos detalles internos. Esto también (quizás en conjunto) sea el problema.
esto es probablemente relevante: ¿Cómo eliminar la constancia de const_iterator?
No creo que esta declaración particular de las necesidades de Meyer deba tomarse con especial preocupación. Cuando desee una operación no modificadora, es mejor usar un const_iterator
. De lo contrario, utilice un iterator
ordinario. Sin embargo, tenga en cuenta lo que es importante: nunca mezcle iteradores, es decir, const
con non-const
. Mientras esté al tanto de esto último, debería estar bien.