Al leer algunos ejemplos de bucles basados en rango, sugieren dos formas principales 1 , 2 , 3 , 4
std::vector<MyClass> vec;
for (auto &x : vec)
{
// x is a reference to an item of vec
// We can change vec's items by changing x
}
o
for (auto x : vec)
{
// Value of x is copied from an item of vec
// We can not change vec's items by changing x
}
Bien.
Cuando no necesitamos cambiar vec
elementos, OMI, los ejemplos sugieren usar una segunda versión (por valor). Por qué no sugieren algo que const
haga referencia (al menos no he encontrado ninguna sugerencia directa):
for (auto const &x : vec) // <-- see const keyword
{
// x is a reference to an const item of vec
// We can not change vec's items by changing x
}
¿No es mejor? ¿No evita una copia redundante en cada iteración mientras es un const
?
const auto &x
es equivalente a su tercera opción.auto&&
cuando no desea hacer una copia innecesaria, y no le importa si la modifica o no, y simplemente quiere trabajar.const
seguro. Sin embargo, si seríaauto const &
, oauto const
tiene poca diferencia. Elegiríaauto const &
ser más consistente.Si tiene un
std::vector<int>
ostd::vector<double>
, entonces está bien usarloauto
(con copia de valor) en lugar deconst auto&
, ya que copiar unint
o undouble
es barato:Pero si tiene un
std::vector<MyClass>
, dondeMyClass
tiene alguna semántica de copia no trivial (por ejemplostd::string
, alguna clase personalizada compleja, etc.), entonces sugiero usarconst auto&
para evitar copias profundas :fuente
Luego dan una sugerencia equivocada.
Porque dan una sugerencia incorrecta :-) Lo que mencionas es correcto. Si solo desea observar un objeto, no es necesario crear una copia, y no es necesario tener una no
const
referencia a él.EDITAR:
Veo que todas las referencias que enlaza proporcionan ejemplos de iteración sobre un rango de
int
valores o algún otro tipo de datos fundamental. En ese caso, dado que copiar unint
no es costoso, crear una copia es básicamente equivalente a (si no es más eficiente que) tener una observaciónconst &
.Sin embargo, este no es el caso en general para los tipos definidos por el usuario. Copiar UDT puede ser costoso, y si no tiene una razón para crear una copia (como modificar el objeto recuperado sin alterar el original), entonces es preferible usar a
const &
.fuente
Voy a ser contrario aquí y decir que no hay necesidad
auto const &
en un rango basado en bucle. Dime si crees que la siguiente función es tonta (no en su propósito, sino en la forma en que está escrita):Aquí, el autor ha creado una referencia constante
v
para usar en todas las operaciones que no modifican v. Esto es una tontería, en mi opinión, y se puede hacer el mismo argumento para usarauto const &
como la variable en un rango basado en bucle en lugar de soloauto &
.fuente
const_iterator
en un bucle for? ¿Cómo se asegura de no cambiar los elementos originales de un contenedor cuando itera sobre él?const_iterator
? Déjame adivinar, el contenedor sobre el que iteras esconst
. ¿Pero por qué esconst
para empezar? ¿En algún lugar lo estás usandoconst
para asegurar qué?const
es como las ventajas de usarprivate
/protected
en las clases. Evita más errores.v
, la implementación estaría bien IMO. Y si el ciclo nunca modifica los objetos a través de los cuales itera, me parece correcto tener una referenciaconst
. Veo su punto, sin embargo. El mío es que el bucle representa una unidad de código muy similar a la función, y dentro de esa unidad no hay instrucciones que necesiten modificar el valor. Por lo tanto, puede "etiquetar" toda la unidad comoconst
, como lo haría con unaconst
función miembro.const &
para el rango basado es tonto, porque escribiste un ejemplo imaginario irrelevante de un programador imaginario que hizo algo tonto con la calificación cv ? ... OK entonces