tipo informacion for evolucion descargar datos creador c++ c++11 foreach

informacion - for c++ 17



¿Es seguro utilizar un bucle for basado en rango de C++ 11 con un rango de valor-init? (1)

Esta pregunta ya tiene una respuesta aquí:

Supongamos que tengo una función que devuelve un std::vector por valor:

std::vector<int> buildVector();

Parece natural iterar sobre el resultado utilizando un rango basado for :

for (int i : buildVector()) { // ... }

Pregunta: ¿Es seguro hacerlo?

Mi lectura de la norma (en realidad, el borrador n4431 ) sugiere que podría no ser así, aunque me cuesta mucho creer que el comité no permitió este uso. Espero que mi lectura sea incorrecta.

La sección 6.5.4 define el rango basado for :

for ( for-range-declaration : expression ) statement

Con la siguiente desugaring:

{ auto && __range = range-init; for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } }

donde range-init es solo ( expression ) , y al menos para los tipos de clase, begin-expr es __range.begin() o begin(__range) , etc.

En mi ejemplo de buildVector , creo que el range-init produce un temporal, que la implementación puede destruir inmediatamente después de que la referencia __range esté vinculada. Esto significaría que la referencia __range podría estar colgando cuando se evalúa el tiempo de begin-expr .

Ciertamente, siempre debería ser seguro escribir esto:

std::vector<int> notATemporary = buildVector(); for (int i : notATemporary) { // ... }

Pero espero no tener que agregar esto a mi lista de errores.


Sí, es perfectamente seguro.

Desde [class.temporary] / 4-5:

Hay dos contextos en los que los temporales se destruyen en un punto diferente al final de la fullexpresión. El primer contexto es cuando se llama a un constructor predeterminado [...]

El segundo contexto es cuando una referencia está vinculada a un temporal. El temporal al que se enlaza la referencia o el temporal que es el objeto completo de un subobjeto al que se enlaza la referencia persiste durante toda la vida útil de la referencia, excepto:

  • Un enlace temporal a un miembro de referencia en un inicializador ctor de un constructor [...]
  • Un enlace temporal a un parámetro de referencia en una llamada de función [...]
  • La duración de un enlace temporal al valor devuelto en una declaración de retorno de función [...]
  • Un enlace temporal a una referencia en un nuevo inicializador [...]

Ninguna de esas excepciones aplica. Por lo tanto, lo temporal persiste durante el tiempo de vida de la referencia, __range , que es el bucle completo.