noexcept
Section: 27.4.3 [basic.string], 27.4.3.8.2 [string.find], 27.4.3.8.4 [string.compare] Status: Resolved Submitter: Jonathan Wakely Opened: 2016-12-05 Last modified: 2023-02-07
Priority: 2
View other active issues in [basic.string].
View all other issues in [basic.string].
View all issues with Resolved status.
Discussion:
Currently some overloads of basic_string::find
are noexcept
and some are not. Historically this
was because some were specified in terms of constructing a temporary basic_string
, which could throw. In
practice creating a temporary (and potentially allocating memory) is a silly implementation, and so they could be
noexcept
. In the C++17 draft most of them have been changed to create a temporary basic_string_view
instead, which can't throw anyway (P0254R2 made those changes).
This is confusing for users, as they need to carefully check which overload their code will resolve to, and consider whether that overload can throw. Refactoring code can change whether it calls a throwing or non-throwing overload. This is an unnecessary burden on users when realistically none of the functions will ever throw.
The find
, rfind
, find_first_of
, find_last_of
, find_first_not_of
and
find_last_not_of
overloads that are defined in terms of basic_string_view
should be noexcept
,
or "Throws: Nothing." for the ones with narrow contracts (even though those narrow contracts are not enforcable
or testable).
The remaining overloads that are still specified in terms of a temporary string could also be noexcept
. They
construct basic_string
of length one (which won't throw for an SSO implementation anyway), but can easily be
defined in terms of basic_string_view
instead.
There's one basic_string::compare
overload that is still defined in terms of a temporary basic_string
,
which should be basic_string_view
and so can also be noexcept
(the other compare
overloads can
throw out_of_range
).
[2016-12-15, Tim Song comments]
The following overloads invoking basic_string_view<charT>(s, n)
are implicitly narrow-contract
(the basic_string_view
constructor requires [s, s+n)
to be a valid range) and should be
"Throws: Nothing" rather than noexcept
:
size_type find(const charT* s, size_type pos, size_type n) const; size_type rfind(const charT* s, size_type pos, size_type n) const; size_type find_first_of(const charT* s, size_type pos, size_type n) const; size_type find_last_of(const charT* s, size_type pos, size_type n) const; size_type find_first_not_of(const charT* s, size_type pos, size_type n) const; size_type find_last_not_of(const charT* s, size_type pos, size_type n) const;
Similarly, the basic_string_view
constructor invoked by this overload of compare
requires
[s, s + traits::length(s))
to be a valid range, and so it should be "Throws: Nothing" rather
than noexcept
:
int compare(const charT* s) const;
[2017-01-27 Telecon]
Priority 2; Jonathan to provide updated wording
[2017-10-22, Marshall comments]
libc++ already has all of these member fns marked as noexcept
[2017-11 Albuquerque Saturday issues processing]
All the fns that take a const char *
are narrow contract, and so can't be noexcept. Should be "Throws: Nothing" instead. Alisdair to re-word.
[2018-08 mailing list discussion]
This will be resolved by Tim's string rework paper.
Resolved by the adoption of P1148 in San Diego.
Proposed resolution:
This wording is relative to N4618.
Change class template synopsis std::basic_string
, 27.4.3 [basic.string], as indicated:
size_type find (basic_string_view<charT, traits> sv, size_type pos = 0) const noexcept; size_type find (const basic_string& str, size_type pos = 0) const noexcept; size_type find (const charT* s, size_type pos, size_type n) const noexcept; size_type find (const charT* s, size_type pos = 0) const; size_type find (charT c, size_type pos = 0) const noexcept; size_type rfind(basic_string_view<charT, traits> sv, size_type pos = npos) const noexcept; size_type rfind(const basic_string& str, size_type pos = npos) const noexcept; size_type rfind(const charT* s, size_type pos, size_type n) const noexcept; size_type rfind(const charT* s, size_type pos = npos) const; size_type rfind(charT c, size_type pos = npos) const noexcept; size_type find_first_of(basic_string_view<charT, traits> sv, size_type pos = 0) const noexcept; size_type find_first_of(const basic_string& str, size_type pos = 0) const noexcept; size_type find_first_of(const charT* s, size_type pos, size_type n) const noexcept; size_type find_first_of(const charT* s, size_type pos = 0) const; size_type find_first_of(charT c, size_type pos = 0) const noexcept; size_type find_last_of (basic_string_view<charT, traits> sv, size_type pos = npos) const noexcept; size_type find_last_of (const basic_string& str, size_type pos = npos) const noexcept; size_type find_last_of (const charT* s, size_type pos, size_type n) const noexcept; size_type find_last_of (const charT* s, size_type pos = npos) const; size_type find_last_of (charT c, size_type pos = npos) const noexcept; size_type find_first_not_of(basic_string_view<charT, traits> sv, size_type pos = 0) const noexcept; size_type find_first_not_of(const basic_string& str, size_type pos = 0) const noexcept; size_type find_first_not_of(const charT* s, size_type pos, size_type n) const noexcept; size_type find_first_not_of(const charT* s, size_type pos = 0) const; size_type find_first_not_of(charT c, size_type pos = 0) const noexcept; size_type find_last_not_of (basic_string_view<charT, traits> sv, size_type pos = npos) const noexcept; size_type find_last_not_of (const basic_string& str, size_type pos = npos) const noexcept; size_type find_last_not_of (const charT* s, size_type pos, size_type n) const noexcept; size_type find_last_not_of (const charT* s, size_type pos = npos) const; size_type find_last_not_of (charT c, size_type pos = npos) const noexcept; basic_string substr(size_type pos = 0, size_type n = npos) const; int compare(basic_string_view<charT, traits> sv) const noexcept; int compare(size_type pos1, size_type n1, basic_string_view<charT, traits> sv) const; template<class T> int compare(size_type pos1, size_type n1, const T& t, size_type pos2, size_type n2 = npos) const; int compare(const basic_string& str) const noexcept; int compare(size_type pos1, size_type n1, const basic_string& str) const; int compare(size_type pos1, size_type n1, const basic_string& str, size_type pos2, size_type n2 = npos) const; int compare(const charT* s) const noexcept; int compare(size_type pos1, size_type n1, const charT* s) const; int compare(size_type pos1, size_type n1, const charT* s, size_type n2) const;
Change 27.4.3.8.2 [string.find] as indicated:
size_type find(const charT* s, size_type pos, size_type n) const noexcept;-5- Returns:
find(basic_string_view<charT, traits>(s, n), pos)
.size_type find(const charT* s, size_type pos = 0) const;-6- Requires:
s
points to an array of at leasttraits::length(s) + 1
elements ofcharT
.-7- Returns:
find(basic_string_view<charT, traits>(s), pos)
.-?- Throws: Nothing.
size_type find(charT c, size_type pos = 0) const noexcept;-8- Returns:
find(basic_string_view<charT, traits>(addressof(c), 1)
.(1, c), pos)
Change [string.rfind] as indicated:
size_type rfind(const charT* s, size_type pos, size_type n) const noexcept;-5- Returns:
rfind(basic_string_view<charT, traits>(s, n), pos)
.size_type rfind(const charT* s, size_type pos = npos) const;-6- Requires:
s
points to an array of at leasttraits::length(s) + 1
elements ofcharT
.-7- Returns:
rfind(basic_string_view<charT, traits>(s), pos)
.-?- Throws: Nothing.
size_type rfind(charT c, size_type pos = npos) const noexcept;-8- Returns:
rfind(basic_string_view<charT, traits>(addressof(c), 1)
.(1, c), pos)
Change [string.find.first.of] as indicated:
size_type find_first_of(const charT* s, size_type pos, size_type n) const noexcept;-5- Returns:
find_first_of(basic_string_view<charT, traits>(s, n), pos)
.size_type find_first_of(const charT* s, size_type pos = 0) const;-6- Requires:
s
points to an array of at leasttraits::length(s) + 1
elements ofcharT
.-7- Returns:
find_first_of(basic_string_view<charT, traits>(s), pos)
.-?- Throws: Nothing.
size_type find_first_of(charT c, size_type pos = 0) const noexcept;-8- Returns:
find_first_of(basic_string_view<charT, traits>(addressof(c), 1)
.(1, c), pos)
Change [string.find.last.of] as indicated:
size_type find_last_of(const charT* s, size_type pos, size_type n) const noexcept;-5- Returns:
find_last_of(basic_string_view<charT, traits>(s, n), pos)
.size_type find_last_of(const charT* s, size_type pos = npos) const;-6- Requires:
s
points to an array of at leasttraits::length(s) + 1
elements ofcharT
.-7- Returns:
find_last_of(basic_string_view<charT, traits>(s), pos)
.-?- Throws: Nothing.
size_type find_last_of(charT c, size_type pos = npos) const noexcept;-8- Returns:
find_last_of(basic_string_view<charT, traits>(addressof(c), 1)
.(1, c), pos)
Change [string.find.first.not.of] as indicated:
size_type find_first_not_of(const charT* s, size_type pos, size_type n) const noexcept;-5- Returns:
find_first_not_of(basic_string_view<charT, traits>(s, n), pos)
.size_type find_first_not_of(const charT* s, size_type pos = 0) const;-6- Requires:
s
points to an array of at leasttraits::length(s) + 1
elements ofcharT
.-7- Returns:
find_first_not_of(basic_string_view<charT, traits>(s), pos)
.-?- Throws: Nothing.
size_type find_first_not_of(charT c, size_type pos = 0) const noexcept;-8- Returns:
find_first_not_of(basic_string_view<charT, traits>(addressof(c), 1)
.(1, c), pos)
Change [string.find.last.not.of] as indicated:
size_type find_last_not_of(const charT* s, size_type pos, size_type n) const noexcept;-5- Returns:
find_last_not_of(basic_string_view<charT, traits>(s, n), pos)
.size_type find_last_not_of(const charT* s, size_type pos = npos) const;-6- Requires:
s
points to an array of at leasttraits::length(s) + 1
elements ofcharT
.-7- Returns:
find_last_not_of(basic_string_view<charT, traits>(s), pos)
.-?- Throws: Nothing.
size_type find_last_not_of(charT c, size_type pos = npos) const noexcept;-8- Returns:
find_last_not_of(basic_string_view<charT, traits>(addressof(c), 1)
.(1, c), pos)
Change 27.4.3.8.4 [string.compare] as indicated:
int compare(const charT* s) const noexcept;-9- Returns:
compare(basic_string_view<charT, traits>(s))
.