Qu'est ce qu'un "span" et quand dois-je utiliser?

Récemment, j'ai reçu des suggestions pour utiliser span<T> dans mon code, ou j'ai vu quelques réponses ici sur le site qui utilisent span - soi-disant une sorte de conteneur. Mais - je ne trouve rien de Tel dans la bibliothèque standard C++.

Quel est Donc ce mystérieux span<T>, et pourquoi (ou quand) est-ce une bonne idée de l'utiliser si elle est non-standard?

140
demandé sur einpoklum 2017-08-17 01:15:05

1 réponses

C'est Quoi?

Un span<T> est:

  • une abstraction Très légère d'une séquence contiguë de valeurs de type T quelque part en mémoire.
  • , Fondamentalement, un struct { T * const ptr; size_t length; }, avec un tas de méthodes pratiques.
  • un type non propriétaire (c'est-à-dire un "reference-type" plutôt qu'un "value type"): il n'alloue jamais ni n'alloue rien et ne garde pas les pointeurs intelligents en vie.

, Il était autrefois connu comme un array_view et même plus tôt que array_ref.

Quand devrais-je l'utiliser?

Tout d'Abord, lors de la pas pour l'utiliser:

  • ne l'utilisez pas dans du code qui pourrait simplement prendre n'importe quelle paire d'itérateurs de début et de fin, comme std::sort, std::find_if, std::copy et toutes ces fonctions de modèle super-génériques.
  • ne l'utilisez pas si vous avez un conteneur de bibliothèque standard (ou un conteneur Boost, etc.) ce que vous savez est la bonne solution pour votre code. Il n'est pas destiné à supplanter l'un d'eux.

Maintenant pour quand pour l'utiliser:

Utilisez span<T> (respectivement, span<const T>) au lieu d'un T* autonome (respectivement const T*) pour lequel vous avez la valeur de longueur. Donc, remplacez des fonctions comme:

  void read_into(int* buffer, size_t buffer_size);

Avec:

  void read_into(span<int> buffer);

Pourquoi devrais-je l'utiliser? Pourquoi est-il une bonne chose?

Oh, les travées sont géniales! Utiliser un span...

  • Signifie que vous pouvez travailler avec cette combinaison pointeur + longueur / début+fin comme vous le feriez avec une fantaisie, conteneur de bibliothèque standard pimped-out, par exemple:

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

    ... mais avec absolument aucun des frais généraux que la plupart des classes de conteneurs encourent.

  • Permet au compilateur de faire plus de travail pour vous parfois. Par exemple, ceci:

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

    Devient ceci:

    int buffer[BUFFER_SIZE];
    read_into(buffer);
    

    ... ce qui fera ce que vous voudriez qu'il fasse. Voir également la directive P. 5 .

  • Est l'alternative raisonnable pour passer const vector<T>& aux fonctions lorsque vous attendez que vos données soient contiguës en mémoire. Plus besoin d'être grondé par des gourous c++ élevés et puissants.

  • Facilite l'analyse statique, de sorte que le compilateur pourrait être en mesure de vous aider à attraper des bugs stupides.

  • permet une instrumentation de compilation de débogage pour la vérification des limites d'exécution (c'est-à-dire que les méthodes de span auront un code de vérification des limites dans #ifndef NDEBUG ... #endif)
  • indique que votre code (qui utilise le span) ne possède pas le pointeur.

Il y a encore plus de motivation pour utiliser span s, que vous pouvez trouver dans les directives de base C++ - mais vous attrapez la dérive.

Pourquoi n'est-ce pas dans la bibliothèque standard (à partir de C++17)?

Il est dans la bibliothèque standard - mais seulement à partir de C++20. La raison en est qu'il est encore assez nouveau dans sa forme actuelle, conçu en conjonction avec le projet C++ Core guidelines, qui ne prend forme que depuis 2015. (Bien que, comme les commentateurs soulignent, il a une histoire antérieure.)

Alors, comment puis-je l'utiliser si ce n'est pas encore dans la bibliothèque standard?

Cela fait partie de la bibliothèque de Support (GSL) de Core Guidelines. Implémentations:

  • Microsoft / Neil Macintosh GSL contient une implémentation autonome: gsl/span
  • GSL-Lite est une implémentation de fichier unique de L'ensemble de GSL (ce n'est pas si Gros, ne vous inquiétez pas), y compris span<T>.

Notez que vous pouvez l'utiliser avec des versions antérieures de la norme de langage-C++11 et C++14, Pas seulement C++17.


Pour en savoir Plus: Vous pouvez trouver tous les détails et les considérations de conception en finale?) proposition officielle, P0122R7: durée: limites-safe vues pour les séquences d'objets par Neal Macintosh et Stephan J. Lavavej. C'est un peu long cependant.

157
répondu einpoklum 2018-06-21 15:14:54