Document number |
P2821R2 |
Date |
2023-5-26 |
Reply-to |
Jarrad J. Waterloo <descender76 at gmail dot com>
|
Audience |
Library Evolution Working Group (LEWG) SG23 Safety and Security |
Table of contents
Changelog
R2
- Corrected
Feature test macro
- Added references to
Usability Enhancements for std::span
R1
- Added verbiage stating that this is not freestanding due to its throwing an exception
- Added feature test macro section
Abstract
This paper proposes the standard adds the at
method to std::span
class in order to address safety, consistency and PR (public relations) concerns.
Request
#if __STDC_HOSTED__ == 1
constexpr reference at(size_type idx) const;
#endif
Returns a reference to the element at specified location idx, with bounds checking.
If idx is not within the range of the container, an exception of type std::out_of_range is thrown.
Parameters
idx - index of the element to return
Return value
Reference to the requested element.
Exceptions
Throws std::out_of_range if idx >= size().
Complexity
Constant.
Motivation
Safety
This new method is safe in the sense that it has defined behavior instead of undefined behavior. Further, the defined behavior is one that can be caught in the code by catching the exception.
Consistency
The std::string
, std::string_view
, std::deque
, std::vector
and std::array
, all have both the unsafe operator[]
and the safe at
function.
|
operator[]
|
at()
|
std::string
|
✓ |
✓ |
std::string_view
|
✓ |
✓ |
std::deque
|
✓ |
✓ |
std::vector
|
✓ |
✓ |
std::array
|
✓ |
✓ |
std::span
|
✓ |
✗ |
Public Relations
C++
keeps giving easy wins to our rivals even though they like to hit below the belt. It is nice when a supporter of a rival language makes an honest comparison.
“In both Rust and C++, there is a method for checked array indexing, and a method for unchecked array indexing. The languages actually agree on this issue. They only disagree about which version gets to be spelled with brackets.” - Being Fair about Memory Safety and Performance
Unfortunately this isn’t totally true.
“std::span<T>
indexing”
…
“std::vector
and std::array
can at least theoretically be used safely because they offer an at()
method which is bounds checked (in practice I’ve never seen this done, but you could imagine a project adopting a static analysis tool which simply banned calls to std::vector<T>::operator[]
). span
does not offer an at()
method, or any other method which performs a bounds checked lookup.”
“Interestingly, both Firefox and Chromium’s backports of std::span do perform bounds checks in operator[], and thus they’ll never be able to safely migrate to std::span.” - Modern C++ Won’t Save Us
Consequently, the programming community in general are encouraged to ask some tough questions.
- Why was
span::at()
not provided in C++20
?
- Was this an accidental omission or was it deliberate?
- If delibrerate, what was the rationale?
- If delibrerate, are the other
at
functions going to be deprecated?
- Why was
span::at()
not added in C++23
?
- Is it going to be in
C++26
?
Ultimately, this becomes a stereotypical example of how C++
traditionally handles safety. This example gets to be pointed at for years/decades to come. All of this could have been avoided, along with more effort of adding this function individually had more consideration been given valid safety concerns.
Feature test macro
Insert the following to [version.syn], header <version>
synopsis:
#define __cpp_lib_span_at 20XXXXL
Implementation Experience
Both of the span lite
and Guidelines Support Library
libraries have this new method implemented for years.
span lite: A single-file header-only version of a C++20-like span for C++98, C++11 and later
Guidelines Support Library
Likely, there are others too such as “Firefox and Chromium’s backports of std::span”.
Summary
Please add the at
method to std::span
class in order to address safety, consistency and PR (public relations) concerns. Also keep ones mind open to an std::expected
version in the future as well as other reasonable safety requests.
References
Jarrad J. Waterloo <descender76 at gmail dot com>
SG23 Safety and Security
span.at()
Table of contents
Changelog
R2
Feature test macro
Usability Enhancements for std::span
[1] [2]R1
Abstract
This paper proposes the standard adds the
at
method tostd::span
class in order to address safety, consistency and PR (public relations) concerns.Request
Returns a reference to the element at specified location idx, with bounds checking.
If idx is not within the range of the container, an exception of type std::out_of_range is thrown.
Parameters idx - index of the element to return
Return value Reference to the requested element.
Exceptions Throws std::out_of_range if idx >= size().
Complexity Constant.
Motivation
Safety
This new method is safe in the sense that it has defined behavior instead of undefined behavior. Further, the defined behavior is one that can be caught in the code by catching the exception.
Consistency
The
std::string
[3],std::string_view
[4],std::deque
[5],std::vector
[6] andstd::array
[7], all have both the unsafeoperator[]
and the safeat
function.operator[]
at()
std::string
std::string_view
std::deque
std::vector
std::array
std::span
Public Relations
C++
keeps giving easy wins to our rivals even though they like to hit below the belt. It is nice when a supporter of a rival language makes an honest comparison.“In both Rust and C++, there is a method for checked array indexing, and a method for unchecked array indexing. The languages actually agree on this issue. They only disagree about which version gets to be spelled with brackets.” - Being Fair about Memory Safety and Performance [6]
Unfortunately this isn’t totally true.
“
std::span<T>
indexing” [7]…
“
std::vector
andstd::array
can at least theoretically be used safely because they offer anat()
method which is bounds checked (in practice I’ve never seen this done, but you could imagine a project adopting a static analysis tool which simply banned calls tostd::vector<T>::operator[]
).span
does not offer anat()
method, or any other method which performs a bounds checked lookup.” [7:1]“Interestingly, both Firefox and Chromium’s backports of std::span do perform bounds checks in operator[], and thus they’ll never be able to safely migrate to std::span.” - Modern C++ Won’t Save Us [7:2]
Consequently, the programming community in general are encouraged to ask some tough questions.
span::at()
not provided inC++20
? [1:1]at
functions going to be deprecated?span::at()
not added inC++23
?C++26
?Ultimately, this becomes a stereotypical example of how
C++
traditionally handles safety. This example gets to be pointed at for years/decades to come. All of this could have been avoided, along with more effort of adding this function individually had more consideration been given valid safety concerns.Feature test macro
Implementation Experience
Both of the
span lite
andGuidelines Support Library
libraries have this new method implemented for years.span lite: A single-file header-only version of a C++20-like span for C++98, C++11 and later
[10]Guidelines Support Library
[11]Likely, there are others too such as “Firefox and Chromium’s backports of std::span”. [9:3]
Summary
Please add the
at
method tostd::span
class in order to address safety, consistency and PR (public relations) concerns. Also keep ones mind open to anstd::expected
version in the future as well as other reasonable safety requests.References
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1024r0.pdf ↩︎ ↩︎
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1024r1.pdf ↩︎ ↩︎
https://en.cppreference.com/w/cpp/string/basic_string/at ↩︎
https://en.cppreference.com/w/cpp/string/basic_string_view/at ↩︎
https://en.cppreference.com/w/cpp/container/deque/at ↩︎
https://en.cppreference.com/w/cpp/container/vector/at ↩︎
https://en.cppreference.com/w/cpp/container/array/at ↩︎
https://www.thecodedmessage.com/posts/unsafe/ ↩︎
https://alexgaynor.net/2019/apr/21/modern-c++-wont-save-us/ ↩︎ ↩︎ ↩︎ ↩︎
https://github.com/martinmoene/span-lite#at ↩︎
https://github.com/microsoft/GSL/blob/main/include/gsl/span_ext#L141 ↩︎