GSL.view
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 (see R.4). Note: References have many opportunities to outlive the objects they refer to (returning a local variable by reference, holding a reference to an element of a vector and doing push_back
, binding to std::max(x, y + 1)
, etc). The Lifetime safety profile aims to address those things, but even so owner<T&>
does not make sense and is discouraged.
The names are mostly ISO standard-library style (lower case and underscore):
T*
// TheT*
is not an owner, might be null; assumed to be pointing to a single element.T&
// TheT&
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*>
// aT*
that owns the object pointed/referred to; might benullptr
.
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*>
andnot_null<owner<Foo*>>
) that must not benullptr
.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)
whereq
is the first element for whichpredicate(*p)
is true
A span<T>
refers to zero or more mutable T
s unless T
is a const
type. All accesses to elements of the span, notably via operator[]
, are guaranteed to be bounds-checked by default.
Note: GSL's
span
(initially calledarray_view
) was proposed for inclusion in the C++ standard library, and was adopted (with changes to its name and interface) except only thatstd::span
does not provide for guaranteed bounds checking. Therefore GSL changedspan
's name and interface to trackstd::span
and should be exactly the same asstd::span
, and the only difference should be that GSLspan
is fully bounds-safe by default. If bounds-safety might affect its interface, then those change proposals should be brought back via the ISO C++ committee to keepgsl::span
interface-compatible withstd::span
. If a future evolution ofstd::span
adds bounds checking,gsl::span
can be removed.
"Pointer arithmetic" is best done within span
s.
A char*
that points to more than one char
but is not a C-style string (e.g., a pointer into an input buffer) should be represented by a span
.
zstring
// achar*
supposed to be a C-style string; that is, a zero-terminated sequence ofchar
ornullptr
czstring
// aconst char*
supposed to be a C-style string; that is, a zero-terminated sequence ofconst
char
ornullptr
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 span<char>
, or if that is impossible because of ABI issues a char*
, rather than a zstring
.
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?