c++ c++11 iterator std

c++ - ¿Por qué std:: begin y std:: end "no son seguros para la memoria"?



c++11 iterator (6)

En esta publicación del blog , Eric Niebler afirma que:

¿Qué está mal con std :: begin y std :: end? ¡Sorpresa! No son seguros para la memoria. Considera lo que hace este código:

extern std::vector<int> get_data(); auto it = std::begin(get_data()); int i = *it; // BOOM

std :: begin tiene dos sobrecargas para valores const y non-const. El problema es que los valores se unen a las referencias constantes de valores, lo que lleva al iterador que cuelga hacia arriba.

Estoy teniendo problemas para entender su punto y por qué es una referencia que cuelga. ¿Podría alguien explicar?


¿Es justo decir que esto es un fallo de seguridad de memoria de std :: begin? No hay una forma ''segura'' de crear un iterador de tal manera que sea válido seguir el puntero una vez que se elimine el contenedor.

Carece de una verificación que tenga otro método, pero no es como si no hubiera una manera de hacer que un iterador derivado de rangos se reviente. Solo tienes que esforzarte un poco más ...


Creo que el punto de vista de Eric sobre std::begin es que acepta silenciosamente un contenedor de valores como un argumento para comenzar. A primera vista, el problema con el código también se ejemplifica en

auto it = get_data().begin();

Pero std::begin es una plantilla de función gratuita, se puede hacer para rechazar rvalues ​​sin necesidad de agregar los calificadores de referencia adecuados a los miembros iniciales de cada contenedor. Al "solo" reenviarlo, se pierde la oportunidad de agregar una capa de seguridad de memoria al código.

Idealmente, el conjunto de sobrecarga podría haberse beneficiado de la adición de

template< class C > void begin( C&& ) = delete;

Ese hubiera causado que el código en la publicación del blog fuera rechazado de plano en el acto.


El vector temporal devuelto por get_data queda fuera del alcance después de que se realiza std::begin . No se mantiene vivo, por it es un iterador en un objeto destruido.


La función get_data devuelve un objeto. Cuando se usa de la manera que se muestra, ese objeto será un objeto temporal , que se destruirá una vez que finalice la expresión completa. El iterador ahora hace referencia a un objeto vectorial que ya no existe, y no puede ser desreferido o usado de ninguna manera útil.


Porque permite la inicialización desde un valor de r, lo que es malo.


de hecho, la función complicada se puede simplificar a dos funciones cortas, como

int& foo(int x){ return x; } int generate_a_int(){ return 42; }

y luego invocarlo foo (generate_a_int ()), se genera un valor temporal, una vez que sale del cuerpo de la función, el valor temporal generado por generate_a_int () se destruye, y luego se produce una referencia a la suspensión ...

¿Entiendes ahora?