En la biblioteca de rangos hay dos tipos de operaciones:
- vistas que son perezosas y requieren que exista el contenedor subyacente.
- acciones que están ansiosas y producen nuevos contenedores como resultado (o modifican los existentes)
Las vistas son ligeras. Los pasa por valor y requiere que los contenedores subyacentes permanezcan válidos y sin cambios.
De la documentación de la gama v3
Una vista es un contenedor ligero que presenta una vista de una secuencia subyacente de elementos de alguna manera personalizada sin mutarla o copiarla. Las vistas son baratas de crear y copiar y tienen una semántica de referencia no propietaria.
y:
Cualquier operación en el rango subyacente que invalide sus iteradores o centinelas también invalidará cualquier vista que se refiera a cualquier parte de ese rango.
La destrucción del contenedor subyacente obviamente invalida todos los iteradores.
En su código, está utilizando vistas específicamente : usted usa ranges::views::transform
. La tubería es simplemente un azúcar sintáctico para que sea fácil escribir de la forma en que está. Debería mirar lo último en la tubería para ver lo que produce, en su caso, es una vista.
Si no hubiera operador de tubería, probablemente se vería así:
ranges::views::transform(my_custom_rng_gen(some_param), my_transform_op)
si hubiera múltiples transformaciones conectadas de esa manera, puede ver lo feo que se pondría.
Por lo tanto, si my_custom_rng_gen
produce algún tipo de contenedor, que transforma y luego devuelve, ese contenedor se destruye y tiene referencias colgantes desde su vista. Si my_custom_rng_gen
es otra vista de un contenedor que vive fuera de estos ámbitos, todo está bien.
Sin embargo, el compilador debería poder reconocer que está aplicando una vista en un contenedor temporal y recibir un error de compilación.
Si desea que su función devuelva un rango como contenedor, debe "materializar" explícitamente el resultado. Para eso, use el ranges::to
operador dentro de la función.
Actualización: para ser más explícito con respecto a su comentario "¿dónde dice la documentación que componer el rango / tubería toma y almacena una vista?"
Pipe es simplemente un azúcar sintáctico para conectar cosas en una expresión fácil de leer. Dependiendo de cómo se use, puede o no devolver una vista. Depende del argumento del lado derecho. En tu caso es:
`<some range> | ranges::views::transform(...)`
Entonces la expresión devuelve lo que sea que views::transform
regrese.
Ahora, leyendo la documentación de la transformación:
A continuación se muestra una lista de los combinadores de rango diferido, o vistas, que proporciona Range-v3, y un resumen sobre cómo se pretende utilizar cada uno.
[...]
views::transform
Dado un rango fuente y una función unaria, devuelve un nuevo rango donde cada elemento resultante es el resultado de aplicar la función unaria a un elemento fuente.
Por lo tanto, devuelve un rango, pero dado que es un operador perezoso, ese rango que devuelve es una vista, con toda su semántica.