mirror of
https://github.com/isocpp/CppCoreGuidelines.git
synced 2025-12-16 12:27:03 +03:00
Proposed specification for gsl::dyn_array (#2261)
* 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>
This commit is contained in:
112
docs/dyn_array.md
Normal file
112
docs/dyn_array.md
Normal file
@@ -0,0 +1,112 @@
|
||||
<!-- $ pandoc -V geometry:margin=1in -V colorlinks=true -o dyn_array.pdf dyn_array.md -->
|
||||
|
||||
# `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]` with `gsl::dyn_array<T>(n)`.
|
||||
* Replace both `foo(T*, size_t)` and `foo(unique_ptr<T[]>&, size_t)` with
|
||||
`foo(gsl::dyn_array<T>&)`.
|
||||
|
||||
It can be thought of like a...
|
||||
|
||||
* `std::array` except the size is specified at runtime.
|
||||
* `std::vector` except 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_array`s can be constructed in the following ways:
|
||||
|
||||
* Default construct a `dyn_array` with no elements:
|
||||
```c++
|
||||
constexpr dyn_array();
|
||||
```
|
||||
|
||||
* Move construct a `dyn_array` from `other`: not possible
|
||||
```c++
|
||||
dyn_array(dyn_array&& other) = delete;
|
||||
```
|
||||
|
||||
* Construct a `dyn_array` with `n` default constructed elements:
|
||||
```c++
|
||||
constexpr explicit dyn_array(size_t n, const Allocator & alloc = Allocator());
|
||||
```
|
||||
|
||||
* Construct a `dyn_array` with `n` elements, each copy constructed from `arg`:
|
||||
```c++
|
||||
constexpr dyn_array(size_t n, const T& arg, const Allocator & alloc = Allocator());
|
||||
```
|
||||
|
||||
* Construct a `dyn_array` with elements from the range `[first, last)`:
|
||||
```c++
|
||||
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_array` from a range:
|
||||
```c++
|
||||
#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_array` with elements from the initializer list:
|
||||
```c++
|
||||
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_**:
|
||||
```c++
|
||||
constexpr T& operator[](size_t);
|
||||
constexpr const T& operator[](size_t) const;
|
||||
```
|
||||
|
||||
* Access the underlying array:
|
||||
```c++
|
||||
constexpr T* data() noexcept;
|
||||
constexpr const T* data() const noexcept;
|
||||
```
|
||||
|
||||
* Return the number of elements in the `dyn_array`:
|
||||
```c++
|
||||
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](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#gslassert-assertions).
|
||||
|
||||
### References
|
||||
* [C++ Named Requirements](https://en.cppreference.com/w/cpp/named_req)
|
||||
* [Microsoft/GSL #1169](https://github.com/microsoft/GSL/issues/1169)
|
||||
* [isocpp/CppCoreGuidelines #2244](https://github.com/isocpp/CppCoreGuidelines/issues/2244)
|
||||
* [n3662](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3662.html)
|
||||
Reference in New Issue
Block a user