GSL.view: Views

These types allow the user to distinguish between owning and non-owning pointers and between pointers to a single object and pointers to the first element of a sequence.

These "views" are never owners.

References are never owners.

The names are mostly ISO standard-library style (lower case and underscore):

  • T* // The T* is not an owner, may be null; assumed to be pointing to a single element.
  • char* // A C-style string (a zero-terminated array of characters); may be null.
  • const char* // A C-style string; may be null.
  • T& // The T& is not an owner and can never be a "null reference"; references are always bound to objects.

The "raw-pointer" notation (e.g. int*) is assumed to have its most common meaning; that is, a pointer points to an object, but does not own it. Owners should be converted to resource handles (e.g., unique_ptr or vector<T>) or marked owner<T*>

  • owner<T*> // a T*that owns the object pointed/referred to; may be nullptr.
  • owner<T&> // a T& that owns the object pointed/referred to.

owner is used to mark owning pointers in code that cannot be upgraded to use proper resource handles. Reasons for that include:

  • Cost of conversion.
  • The pointer is used with an ABI.
  • The pointer is part of the implementation of a resource handle.

An owner<T> differs from a resource handle for a T by still requiring an explicit delete.

An owner<T> is assumed to refer to an object on the free store (heap).

If something is not supposed to be nullptr, say so:

  • not_null<T> // T is usually a pointer type (e.g., not_null<int*> and not_null<owner<Foo*>>) that may not be nullptr. T can be any type for which ==nullptr is meaningful.

  • span<T> // [p:p+n), constructor from {p, q} and {p, n}; T is the pointer type

  • span_p<T> // {p, predicate} [p:q) where q is the first element for which predicate(*p) is true
  • string_span // span<char>
  • cstring_span // span<const char>

A span<T> refers to zero or more mutable Ts unless T is a const type.

"Pointer arithmetic" is best done within spans. A char* that points to something that is not a C-style string (e.g., a pointer into an input buffer) should be represented by a span. There is no really good way to say "pointer to a single char" (string_span{p, 1} can do that, and T* where T is a char in a template that has not been specialized for C-style strings).

  • zstring // a char* supposed to be a C-style string; that is, a zero-terminated sequence of char or null_ptr
  • czstring // a const char* supposed to be a C-style string; that is, a zero-terminated sequence of const char or null_ptr

Logically, those last two aliases are not needed, but we are not always logical, and they make the distinction between a pointer to one char and a pointer to a C-style string explicit. A sequence of characters that is not assumed to be zero-terminated should be a char*, rather than a zstring. French accent optional.

Use not_null<zstring> for C-style strings that cannot be nullptr. ??? Do we need a name for not_null<zstring>? or is its ugliness a feature?