Recientemente he recibido sugerencias para el uso de span<T>‘s en mi código, o han visto algunas respuestas aquí en el sitio que uso span‘s – supuestamente algún tipo de contenedor. Pero no puedo encontrar nada de eso en el estándar de C++ biblioteca.

Entonces, ¿qué es este misterioso span<T>, y por qué (o cuando) es una buena idea utilizar si no estándar?

  • std::span fue propuesto en el año 2017. Aplica C++17 o C++20. Véase también P0122R5, span: límites-seguro de vistas para las secuencias de objetos. ¿Desea realmente el objetivo de que el idioma? Pasarán años antes de que los compiladores de ponerse al día.
  • span son utilizables con C++11… como gsl::span en lugar de std::span. Véase también mi respuesta.
InformationsquelleAutor einpoklum | 2017-08-16

1 Comentario

  1. 205

    ¿Qué es?

    Un span<T> es:

    • Muy ligero, la abstracción de una secuencia contigua de valores de tipo T en algún lugar de la memoria.
    • Básicamente un struct { T * ptr; size_t length; } con un montón de métodos de conveniencia.
    • Un no-ser dueño de tipo (es decir, un «tipo de referencia» en lugar de un «tipo de valor»): nunca Se asigna ni cancela la asignación de nada y no mantener punteros inteligentes vivo.

    Anteriormente era conocida como una array_view e incluso antes, ya que array_ref.

    Cuando debo usar?

    Primero, cuando no a utilizar:

    • No lo utilice en el código que podría tomar cualquier par de start & final iteradores, como std::sort, std::find_if, std::copy y todos esos super-genérica de funciones con plantillas.
    • No lo use si usted tiene una biblioteca estándar de contenedor (o un Impulso de contenedores, etc.) que como saben, es el más adecuado para su código. No es la intención de suplantar a cualquiera de ellos.

    Ahora para cuándo usarlo:

    Uso span<T> (respectivamente, span<const T>) en lugar de un pie T* (respectivamente const T*) para los que tienen el valor de longitud. Así, sustituir las funciones como:

      void read_into(int* buffer, size_t buffer_size);

    con:

      void read_into(span<int> buffer);

    ¿Por qué debo utilizar? ¿Por qué es una buena cosa?

    Oh, las luces son impresionantes! El uso de un span

    • significa que usted puede trabajar con ese puntero+longitud /inicio+fin puntero combinación como lo haría con una fantasía, pimped out de la biblioteca estándar de contenedor, por ejemplo:

      • for (auto& x : my_span) { /* do stuff */}
      • std::find_if(my_span.begin(), my_span.end(), some_predicate);

      … pero con absolutamente nada de la sobrecarga de la mayoría de las clases de contenedor incurrir.

    • permite que el compilador de hacer más trabajo para usted a veces. Por ejemplo, este:

      int buffer[BUFFER_SIZE];
      read_into(buffer, BUFFER_SIZE);

      se convierte en esto:

      int buffer[BUFFER_SIZE];
      read_into(buffer);

      … que va a hacer lo que se desea hacer. Véase también La Pauta De La P. 5.

    • es la alternativa razonable a pasar const vector<T>& a las funciones cuando se espera que los datos sean contiguos en memoria. No más llegar regañados por alto y poderoso C++ gurús.

    • facilita el análisis estático, por lo que el compilador podría ser capaz de ayudarle a ponerse tontos errores.
    • permite la depuración de la recopilación de instrumentación para el tiempo de ejecución de la comprobación de límites (es decir, span‘s métodos tienen algunas comprobación de límites de código dentro de #ifndef NDEBUG#endif)
    • indica que el código (que es el uso de la extensión) no posee el puntero.

    Incluso hay más motivación para el uso de spans, que se puede encontrar en la C++ pautas básicas – pero se puede coger a la deriva.

    ¿Por qué no es en la biblioteca estándar (como la de C++17)?

    Es en la biblioteca estándar – pero sólo a partir de C++20. La razón es que es todavía bastante nuevo en su forma actual, concebido en conjunto con la C++ pautas básicas proyecto, que sólo ha ido tomando forma desde 2015. (Aunque como comentaristas punto, tiene una historia más temprana.)

    Entonces, ¿cómo lo puedo utilizar si no está en la biblioteca estándar todavía?

    Es parte de la Pautas Básicas‘s de la Biblioteca de Soporte (GSL). Implementaciones:

    • Microsoft /Neil Macintosh GSL contiene una independiente de la aplicación: gsl/span
    • GSL-Lite es de un solo archivo de la aplicación de la totalidad de la GSL (no es muy importante, no te preocupes), incluyendo span<T>.

    Tenga en cuenta que usted puede utilizar con versiones anteriores de la lengua estándar C++11 y C++14, no solo C++17.


    Leer más: puede encontrar todos los detalles y consideraciones de diseño en el final oficial de la propuesta antes de C++17, P0122R7: span: límites-seguro de vistas para las secuencias de objetos por Neal Macintosh y Stephan J. Lavavej. Es un poco largo, aunque. También, en C++20, el lapso de comparación semántica cambiado (siguiente este breve documento por Tony van Eerd).

    • No read_into(int* from, int* to) estar más en línea con el habitual (iterator) basado en el enfoque de la biblioteca estándar?
    • Yo quería un pequeño ejemplo. Tanto tu y mi variante de las funciones que probablemente no sería algo que realmente pondría en una biblioteca de todos modos. También, tenga en cuenta que con su variante, no es posible saber cuánto usted necesita para leer, así que tal vez te refieres a read_into(int* from, int* to, size_t n)? Que se mencionan en las Directrices básicas documento como un «mal ejemplo» en realidad.
    • oh, no, eso no es a lo que me refería. Diferente: read_into(int* begin, int* end)
    • Ah, bueno, la cosa es que, con un span<T>, usted no sabe/no importa si internamente tiene int* begin; size_t length o int* begin; int* end; Así que no creo que importe mucho.
    • Tendría más sentido para estandarizar una gama general (apoyo de iterador+sentinel y iterador+longitud, tal vez incluso iterador+sentinel+longitud) y hacer que abarcan un simple typedef. Porque, usted sabe, que es más genérico.
    • Lástima que no estandarizar la representación, por lo que podría ser utilizado para la interoperabilidad entre diferentes idiomas.
    • Los rangos están llegando a C++, pero la propuesta actual (por Eric Niebler) requiere el apoyo de los Conceptos. Así que no antes de C++20.
    • Puede usted explicar cómo span puede saber el tamaño de un array, mientras se construye sólo por la matriz puntero solo ? Es debido a la duración, pueden leer los bytes junto al puntero para obtener el tamaño de la información (supongo que estos bytes son también asignados por new o malloc, por lo que puede correctamente delete más tarde)? No puedo encontrar cualquier artículo acerca de esto, y de que la sugerencia se agradece. Gracias.
    • Matrices inmediatamente no decaer en los punteros. trate de hacer std::cout << sizeof(buffer) << '\n' y verá usted consigue 100 sizeof(int)’s.
    • Veo, sí, tienes razón. Es cierto que el compilador puede decir el tamaño de buffer, ya que es conocido en tiempo de compilación ? sizeof es también el momento de la compilación de la función. Pero, ¿qué acerca de la memoria asignada dinámicamente por new o malloc? Puede span trabajar con ellos ?
    • Se puede decir que el tamaño del búfer porque búfer se define como una matriz de tamaño. Que no tiene nada que ver con el tiempo de compilación vs tiempo de ejecución. Lea las respuestas a esta pregunta de aquí ASÍ.
    • Es perfectamente aceptable para auto-responder a las preguntas.
    • ¿Cuáles son las ventajas/desventajas frente a la std::array?
    • es un contenedor, es propietaria de los valores. span es no poseer
    • es una bestia completamente diferente. Su longitud es fija en tiempo de compilación y es un valor de tipo más bien de un tipo de referencia, como Caleth explicó.
    • Ejemplo alrededor de read_into(buffer); es la clave de la cuestión que estoy teniendo aquí. Nativo de la matriz de referencia, con mucho éxito, mata a los ‘span’ idea en ese escenario. Es «fundamental tipo de vocabulario» de la misma manera std::span podría ser. I «necesidad» esto claramente mencionado en ‘span’ júbilo del.
    • sdra ejemplo de conjunto de

Dejar respuesta

Please enter your comment!
Please enter your name here