una tipos switch funciones funcion ejemplos dev crear c++ c++-faq cpp-core-guidelines guideline-support-library std-span

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 un T* independiente (respectivamente const 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).