* final draft of proposal * fix alloc formal * resolve ambiguity and fix TODO * some wording improvements * apply some feedback after offline review w/ @GabrielDosReis * Update specification after review from C++ Core Guidelines - Make sure iterators and references cannot be invalidated by any operations (besides destruction). - Update specification to annotate that some functions require certain language features (ranges and concepts). - Remove dependence on "Container" named requirements because they require iterator-invalidating behavior. - Explicitly add default and move constructors. - Fix some typos * Update dyn_array documentation reflecting editors' feedback Clarified that `gsl::dyn_array` cannot be moved or copied. Updated the FAQ section to emphasize that it is a fixed-size array without iterator/pointer-invalidating operations. * Update FAQ regarding gsl::dyn_array usage Clarified the purpose of gsl::dyn_array in the FAQ section. --------- Co-authored-by: Gabriel Dos Reis <GabrielDosReis@users.noreply.github.com>
4.0 KiB
gsl::dyn_array<T, Allocator>
gsl::dyn_array is a dynamic array that is intended to be a replacement for slinging
around raw pointers and sizes. Notably, it owns all of its elements. It should replace
the following idioms:
- Replace
new T[n]withgsl::dyn_array<T>(n). - Replace both
foo(T*, size_t)andfoo(unique_ptr<T[]>&, size_t)withfoo(gsl::dyn_array<T>&).
It can be thought of like a...
std::arrayexcept the size is specified at runtime.std::vectorexcept it can neither shrink nor grow.
By design, gsl::dyn_array is not a Container as defined by the C++ Named
Requirements because we want to avoid the invalidation of iterators or references to
gsl::dyn_array objects. Furthermore, by design, there is no support for operations
(other than destruction) that can invalidate iterators or pointers into the sequence
owned by a gsl::dyna_array object. An gsl::dyn_array object cannot be moved,
nor can it be copied.
Construction
gsl::dyn_arrays can be constructed in the following ways:
- Default construct a
dyn_arraywith no elements:
constexpr dyn_array();
- Move construct a
dyn_arrayfromother: not possible
dyn_array(dyn_array&& other) = delete;
- Construct a
dyn_arraywithndefault constructed elements:
constexpr explicit dyn_array(size_t n, const Allocator & alloc = Allocator());
- Construct a
dyn_arraywithnelements, each copy constructed fromarg:
constexpr dyn_array(size_t n, const T& arg, const Allocator & alloc = Allocator());
- Construct a
dyn_arraywith elements from the range[first, last):
template <typename InputIt>
#ifdef __cpp_lib_concepts
requires(std::input_iterator<InputIt>)
#endif /* __cpp_lib_concepts */
constexpr dyn_array(InputIt first, InputIt last, const Allocator & alloc = Allocator());
- Construct a
dyn_arrayfrom a range:
#ifdef __cpp_lib_containers_range
template <typename R>
requires(std::ranges::range<R>)
constexpr dyn_array(std::from_range_t, R&& r, const Allocator & alloc = Allocator());
#endif /* __cpp_lib_containers_range */
- Construct a
dyn_arraywith elements from the initializer list:
constexpr dyn_array(std::initializer_list<T>, const Allocator & alloc = Allocator());
Operations
In addition to the operations required by the named requirements, gsl::dyn_array will
support the following operations:
- Access the specified element with bounds checking:
constexpr T& operator[](size_t);
constexpr const T& operator[](size_t) const;
- Access the underlying array:
constexpr T* data() noexcept;
constexpr const T* data() const noexcept;
- Return the number of elements in the
dyn_array:
constexpr size_t size() const noexcept;
FAQ
Why no push_back (and friends)?
gsl::dyn_array is intended to be a fixed-size array and all objects should be
constructed at creation. It supports no iterator/pointer-invalidating operation.
Why does gsl::dyn_array not conform to the Container Named Requirements?
gsl::dyn_array is intended to be a safer replacement for raw pointers and sizes. We
don't want users to accidentally use it in a way that would be unsafe. For example,
gsl::dyn_array does not have copy or move operations. This is because it
would be possible to invalidate existing iterators and references.
Bounds Checking Semantics
If an out-of-bounds access (read or write) is attempted, gsl::dyn_array should follow
the contract violation strategy outlined in GSL.assert: Assertions.