c++ - tipos - ¿Qué es un "intervalo" y cuándo debo usar uno?
tipos de funciones en c++ (1)
Recientemente recibí sugerencias para usar
span<T>
en mi código, o he visto algunas respuestas aquí en el sitio que usan
span
- supuestamente algún tipo de contenedor.
Pero no puedo encontrar algo así en la biblioteca estándar de C ++.
Entonces, ¿qué es este
span<T>
misterioso
span<T>
, y por qué (o cuándo) es una buena idea usarlo si no es estándar?
¿Qué es?
Un
span<T>
es:
- Una abstracción muy ligera de una secuencia contigua de valores de tipo T en algún lugar de la memoria.
-
Básicamente una
struct { T * ptr; size_t length; }
struct { T * ptr; size_t length; }
struct { T * ptr; size_t length; }
con un montón de métodos convenientes. - Un tipo no propietario (es decir, un "reference-type" lugar de un "tipo de valor"): nunca asigna ni desasigna nada y no mantiene vivos los punteros inteligentes.
Anteriormente se conocía como
array_view
e incluso antes como
array_ref
.
¿Cuándo debería usarlo?
Primero, cuándo no usarlo:
-
No lo use en un código que pueda tomar cualquier par de iteradores de inicio y fin, como
std::sort
,std::find_if
,std::copy
y todas esas funciones con plantilla súper genéricas. - No lo use si tiene un contenedor de biblioteca estándar (o un contenedor Boost, etc.) que sabe que es el adecuado para su código. No está destinado a suplantar a ninguno de ellos.
Ahora para saber cuándo usarlo realmente:
Use
span<T>
(respectivamente,span<const T>
) en lugar de unT*
independiente (respectivamenteconst T*
) para el que tiene el valor de longitud. Entonces, reemplace funciones como:
void read_into(int* buffer, size_t buffer_size);
con:
void read_into(span<int> buffer);
¿Por qué debería usarlo? ¿Por qué es algo bueno?
¡Oh, los tramos son increíbles!
Usando un
span
...
-
significa que puede trabajar con esa combinación de puntero + longitud / inicio + fin como lo haría con un contenedor de biblioteca estándar sofisticado, por ejemplo:
-
for (auto& x : my_span) { /* do stuff */ }
-
std::find_if(my_span.begin(), my_span.end(), some_predicate);
... pero sin ninguno de los gastos generales en que incurre la mayoría de las clases de contenedores.
-
-
permite que el compilador trabaje más por usted a veces. Por ejemplo, esto:
int buffer[BUFFER_SIZE]; read_into(buffer, BUFFER_SIZE);
se convierte en esto:
int buffer[BUFFER_SIZE]; read_into(buffer);
... que hará lo que quieras que haga. Véase también la directriz P.5 .
-
es la alternativa razonable para pasar
const vector<T>&
a funciones cuando espera que sus datos sean contiguos en la memoria. No más ser regañado por los grandes y poderosos gurús de C ++. - facilita el análisis estático, por lo que el compilador podría ayudarlo a detectar errores tontos.
-
permite la instrumentación de compilación de depuración para la verificación de límites de tiempo de ejecución (es decir, los métodos de
span
tendrán algún código de verificación de límites dentro de#ifndef NDEBUG
...#endif
) - indica que su código (que usa el span) no posee el puntero.
Hay aún más motivación para usar
span
s, que puedes encontrar en las
pautas básicas de C ++
, pero captas la deriva.
¿Por qué no está en la biblioteca estándar (a partir de C ++ 17)?
Está en la biblioteca estándar, pero solo a partir de C ++ 20. La razón es que todavía es bastante nueva en su forma actual, concebida en conjunto con el proyecto de directrices centrales de C ++ , que solo ha estado tomando forma desde 2015. (Aunque como señalan los comentaristas, tiene una historia anterior).
Entonces, ¿cómo lo uso si aún no está en la biblioteca estándar?
Es parte de la Biblioteca de soporte de las Directrices básicas (GSL). Implementaciones:
-
El
GSL
Microsoft / Neil Macintosh contiene una implementación independiente:
gsl/span
-
GSL-Lite
es una implementación de un solo archivo de todo el GSL (no es tan grande, no se preocupe), incluido
span<T>
.
Tenga en cuenta que puede usarlo con versiones anteriores del lenguaje estándar: C ++ 11 y C ++ 14, no solo C ++ 17.
Lectura adicional: puede encontrar todos los detalles y consideraciones de diseño en la propuesta oficial final antes de C ++ 17, P0122R7: span: vistas seguras para las secuencias de objetos de Neal Macintosh y Stephan J. Lavavej. Aunque es un poco largo. Además, en C ++ 20, la semántica de comparación de tramo cambió (siguiendo este breve artículo de Tony van Eerd).