GSL: Guideline support library
The GSL is a small library of facilities designed to support this set of guidelines. Without these facilities, the guidelines would have to be far more restrictive on language details.
The Core Guidelines support library is defined in namespace gsl and the names may be aliases for standard library or other well-known library names. Using the (compile-time) indirection through the gsl namespace allows for experimentation and for local variants of the support facilities.
The GSL is header only, and can be found at GSL: Guideline support library. The support library facilities are designed to be extremely lightweight (zero-overhead) so that they impose no overhead compared to using conventional alternatives. Where desirable, they can be "instrumented" with additional functionality (e.g., checks) for tasks such as debugging.
These Guidelines assume a variant type, but this is not currently in GSL.
Eventually, use the one voted into C++17.
Summary of GSL components:
We plan for a "ISO C++ standard style" semi-formal specification of the GSL.
We rely on the ISO C++ standard library and hope for parts of the GSL to be absorbed into the standard library.
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. 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, may 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; may 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>//Tis usually a pointer type (e.g.,not_null<int*>andnot_null<owner<Foo*>>) that may not benullptr.Tcan be any type for which==nullptris meaningful.span<T>//[p:p+n), constructor from{p, q}and{p, n};Tis the pointer typespan_p<T>//{p, predicate}[p:q) whereqis the first element for whichpredicate(*p)is truestring_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 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 ofcharornullptrczstring// aconst char*supposed to be a C-style string; that is, a zero-terminated sequence ofconstcharornullptr
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?
GSL.owner: Ownership pointers
unique_ptr<T>// unique ownership:std::unique_ptr<T>shared_ptr<T>// shared ownership:std::shared_ptr<T>(a counted pointer)stack_array<T>// A stack-allocated array. The number of elements are determined at construction and fixed thereafter. The elements are mutable unlessTis aconsttype.dyn_array<T>// ??? needed ??? A heap-allocated array. The number of elements are determined at construction and fixed thereafter. The elements are mutable unlessTis aconsttype. Basically aspanthat allocates and owns its elements.
GSL.assert: Assertions
Expects// precondition assertion. Currently placed in function bodies. Later, should be moved to declarations.// `Expects(p)` terminates the program unless `p == true` // `Expect` in under control of some options (enforcement, error message, alternatives to terminate)Ensures// postcondition assertion. Currently placed in function bodies. Later, should be moved to declarations.
These assertions is currently macros (yuck!) and must appear in function definitions (only)
pending standard commission decisions on contracts and assertion syntax.
See the contract proposal; using the attribute syntax,
for example, Expects(p!=nullptr) will become [[expects: p!=nullptr]].
GSL.util: Utilities
finally//finally(f)makes afinal_action{f}with a destructor that invokesfnarrow_cast//narrow_cast<T>(x)isstatic_cast<T>(x)narrow//narrow<T>(x)isstatic_cast<T>(x)ifstatic_cast<T>(x) == xor it throwsnarrowing_error[[implicit]]// "Marker" to put on single-argument constructors to explicitly make them non-explicit.move_owner//p = move_owner(q)meansp = qbut ???
GSL.concept: Concepts
These concepts (type predicates) are borrowed from Andrew Sutton's Origin library, the Range proposal, and the ISO WG21 Palo Alto TR. They are likely to be very similar to what will become part of the ISO C++ standard. The notation is that of the ISO WG21 Concepts TS. Most of the concepts below are defined in the Ranges TS.
RangeString// ???Number// ???SortablePointer// A type with*,->,==, and default construction (default construction is assumed to set the singular "null" value); see smart pointersUnique_ptr// A type that matchesPointer, has move (not copy), and matches the Lifetime profile criteria for auniqueowner type; see smart pointersShared_ptr// A type that matchesPointer, has copy, and matches the Lifetime profile criteria for asharedowner type; see smart pointersEqualityComparable// ???Must we suffer CaMelcAse???ConvertibleCommonBooleanIntegralSignedIntegralSemiRegular// ??? Copyable?RegularTotallyOrderedFunctionRegularFunctionPredicateRelation- ...
Smart pointer concepts
Described in Lifetimes paper.