Title
Inconsistency between `std::basic_string`'s `data()` and `operator[]` specification
Status
new
Section
[string.access]
Submitter
Peter Bindels

Created on 2025-09-16.00:00:00 last changed 3 weeks ago

Messages

Date: 2025-09-21.06:08:34

Proposed resolution:

This wording is relative to N5014.

  1. Modify [string.access] as indicated:

    constexpr const_reference operator[](size_type pos) const;
    constexpr       reference operator[](size_type pos);
    

    -1- Hardened preconditions: pos <= size() is `true`.

    -2- Returns: `*(begin() + pos)` if pos <= size(). Otherwise, returns a reference to an object of type `charT` with value `charT()`, where modifying the object to any value other than `charT()` leads to undefined behavior.

    -3- Throws: Nothing.

    -4- Complexity: Constant time.

    -?- Remarks The program shall not modify the value stored at `size()` to any value other than `charT()`; otherwise, the behavior is undefined

Date: 2025-09-16.00:00:00

From the working draft N5014, the specification for `operator[]` in [string.access] p2 says:

Returns: *(begin() + pos) if pos < size(). Otherwise, returns a reference to an object of type `charT` with value `charT()`, where modifying the object to any value other than `charT()` leads to undefined behavior.

The specification for data() in [string.accessors] p1 (and p4) says, however:

Returns: A pointer `p` such that `p + i == addressof(operator[](i))` for each `i` in `[0, size()]`.

The former implies that `str[str.size()]` is allowed to be the address of any null terminator, while the latter restricts it to only being the null terminator belonging to the string.

Suggested fix: Change wording around `operator[]` to

Returns: `*(begin() + pos)` if pos <= size(). The program shall not modify the value stored at `size()` to any value other than `charT()`; otherwise, the behavior is undefined.

This moves it inline with the `data()` specification. Given the hardened precondition that pos <= size() this does not change behavior for any in-contract access, and we do not define what the feature does when called with broken preconditions. I have been looking at the latter but that will be an EWG paper instead.

History
Date User Action Args
2025-09-21 05:42:21adminsetmessages: + msg15072
2025-09-16 00:00:00admincreate