What is a “span” and when should I use one?

2019-01-01 10:11发布

Recently I've gotten suggestions to use span<T>'s in my code, or have seen some answers here on the site which use span's - supposedly some kind of container. But - I can't find anything like that in the C++ standard library.

So what is this mysterious span<T>, and why (or when) is it a good idea to use it if it's non-standard?

1条回答
心情的温度
2楼-- · 2019-01-01 11:07

What is it?

A span<T> is:

  • A very lightweight abstraction of a contiguous sequence of values of type T somewhere in memory.
  • Basically a struct { T * const ptr; size_t length; } with a bunch of convenience methods.
  • A non-owning type (i.e. a "reference-type" rather than a "value type"): It never allocates nor deallocates anything and does not keep smart pointers alive.

It was formerly known as an array_view and even earlier as array_ref.

When should I use it?

First, when not to use it:

  • Don't use it in code that could just take any pair of start & end iterators, like std::sort, std::find_if, std::copy and all of those super-generic templated functions.
  • Don't use it if you have a standard library container (or a Boost container etc.) which you know is the right fit for your code. It's not intended to supplant any of them.

Now for when to actually use it:

Use span<T> (respectively, span<const T>) instead of a free-standing T* (respectively const T*) for which you have the length value. So, replace functions like:

  void read_into(int* buffer, size_t buffer_size);

with:

  void read_into(span<int> buffer);

Why should I use it? Why is it a good thing?

Oh, spans are awesome! Using a span...

  • means that you can work with that pointer+length / start+end pointer combination like you would with a fancy, pimped-out standard library container, e.g.:

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

    ... but with absolutely none of the overhead most container classes incur.

  • lets the compiler do more work for you sometimes. For example, this:

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

    becomes this:

    int buffer[BUFFER_SIZE];
    read_into(buffer);
    

    ... which will do what you would want it to do. See also Guideline P.5.

  • is the reasonable alternative to pass const vector<T>& to functions when you expect your data to be contiguous in memory. No more getting scolded by high-and-mighty C++ gurus.

  • facilitates static analysis, so the compiler might be able to help you catch silly bugs.

  • allows for debug-compilation instrumentation for runtime bounds-checking (i.e. span's methods will have some bounds-checking code within #ifndef NDEBUG ... #endif)
  • indicates that your code (that's using the span) doesn't own the pointer.

There's even more motivation for using spans, which you could find in the C++ core guidelines - but you catch the drift.

Why is it not in the standard library (as of C++17)?

It is in the standard library - but only as of C++20. The reason is that it's still pretty new in its current form, conceived in conjunction with the C++ core guidelines project, which has only been taking shape since 2015. (Although as commenters point out, it has earlier history.)

So how do I use it if it's not in the standard library yet?

It's part of the Core Guidelines's Support Library (GSL). Implementations:

  • Microsoft / Neil Macintosh's GSL contains a standalone implementation: gsl/span
  • GSL-Lite is a single-file implementation of the whole GSL (it's not that big, don't worry), including span<T>.

Note that you can use it with earlier versions of the language standard - C++11 and C++14, not just C++17.


Further reading: You can find all the details and design considerations in the final official proposal before C++17, P0122R7: span: bounds-safe views for sequences of objects by Neal Macintosh and Stephan J. Lavavej. It's a bit long though. Also, in C++20, the span comparison semantics changed (following this short paper by Tony van Eeerd).

查看更多
登录 后发表回答