c++ - En ''for(auto c: str)'', ¿qué es exactamente c?
loops range (7)
En ''
for (auto c : str)
'', ¿qué es exactamente c?
c es una variable local con almacenamiento automático dentro del alcance de la declaración de rango.
Su tipo se deducirá porque usó
auto
.
En caso de
string str="ARZ";
, el tipo deducido será
char
.
Presumiblemente, c es solo un puntero en el vector
No hay vector, y c no es un puntero.
Es un
char
.
Comprender lo que hace el rango puede ayudar.
Es equivalente a hacer lo siguiente (las variables prefijadas
__
no son accesibles para el programador; son conceptuales para el comportamiento del bucle):
{
auto && __range = range_expression;
auto __begin = begin_expr;
auto __end = end_expr;
for (; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
O, en este caso particular:
{
auto && __range = str;
auto __begin = range.begin();
auto __end = range.end();
for ( ; __begin != __end; ++__begin) {
auto c = *__begin; // note here
cout << (void*)&c << endl;
}
}
Tenga en cuenta que si usa
auto&
, entonces se deducirá que c es una referencia a char.
La aplicación del operador addressof a una referencia no producirá la dirección de la variable de referencia, sino la dirección del objeto referido.
En este caso, el objeto referido sería el carácter dentro de la cadena.
Si declaro:
string s = "ARZ";
Y luego ejecuta el siguiente código:
for (auto& c : s) {
cout << (void*)&c << endl;
}
los resultados corresponderán a las direcciones de
s[0]
,
s[1]
y
s[2]
respectivamente.
Si elimino el
&
y ejecuto:
for (auto c : s) {
cout << (void*)&c << endl;
}
La dirección de
c
es siempre la misma.
Presumiblemente,
c
es solo un puntero en el vector y su valor avanza por
sizeof(char)
con cada bucle, pero me resulta difícil entender por qué no estoy obligado a escribir
*c
para acceder a los valores de cadena de caracteres.
Y finalmente si corro:
for (auto c: s) {
c=''?'';
cout << c << endl;
}
Imprime 3 signos de interrogación.
¿Me resulta difícil comprender qué es realmente
c
?
En ''for (auto c: str)'', ¿qué es exactamente c?
Es una variable local cuyo alcance es el bloque completo y tiene el tipo
char
.
for (auto c : str) { loop_statement }
es equivalente a
{
for (auto __begin = str.begin(), __end = str.end(); __begin != __end; ++__begin) {
auto c = *__begin;
loop_statement
}
}
En algunas implementaciones, en algunas condiciones, dado que la vida útil de
c
finaliza antes de que comience la vida útil de
c
de la próxima iteración, se asigna en el mismo lugar y obtiene la misma dirección.
No puedes confiar en eso.
Cuando usa referencias, la referencia
c
es una referencia a un carácter dentro de la cadena.
Cuando no usa referencias,
c
es una variable
char
simple, que contiene una
copia
del carácter en la cadena.
La razón por la que la variante sin referencia proporciona el mismo puntero para todas las iteraciones es simplemente un detalle de implementación, donde el compilador reutiliza el espacio para la variable
c
dentro de cada iteración.
En este rango para bucle
for (auto c: s) {c=''?''; cout << c << endl;}
hay tres iteraciones porque el tamaño de la cadena
s
es igual a
3
.
Dentro del bucle, el valor asignado del objeto
c
se ignora y el objeto es reasignado por el carácter
''?''
.
Entonces tres personajes
''?''
son emitidos
El tipo de la variable local c es
char
que es el tipo de valor de la clase
std::string
En este rango para bucle
for (auto& c : s) cout << (void*)&c << endl;
la variable
c
tiene un tipo referenciado más precisamente el tipo
char &
.
Entonces, en este bucle, se emiten las direcciones de los objetos referenciados.
Es decir, en este bucle se envían las direcciones de los elementos de la cadena.
En este rango para bucle
for (auto c : s) cout << (void*)&c << endl;
se emite la dirección de la misma variable local
c
.
Si no conoce el tipo, puede dejar que el compilador le diga:
#include <string>
template <typename T>
struct tell_type;
int main(){
std::string s = "asdf";
for (auto& c : s) {
tell_type<decltype(c)>();
}
}
Tenga en cuenta que no hay una definición para
tell_type
, por lo tanto, esto dará como resultado un error en la línea de:
error: implicit instantiation of undefined template ''tell_type<char>''
Y de manera similar
error: implicit instantiation of undefined template ''tell_type<char &>''
para el
for (auto& ...
loop.
c
es
char
.
La sintaxis puede ser engañosa hasta que la tenga debajo de la piel (pero tiene sentido).
for (auto c : s) //*distinct object* (think: a copy usually)
for (auto& c : s) //reference into the string (can modify string)
Corto:
use
auto&
cuando necesite modificar el contenido.
for (auto& c : s)
c
es una
reference
a un personaje (
char&
)
Este bucle es más o menos equivalente a C:
for (char* c=str; *c; ++c)
for (auto c : s)
c
es un personaje (
char
)
Este bucle es más o menos equivalente a C:
int i=0;
for (char c=str[i]; i<strlen(str); c=str[++i])