noexcept
issues in basic_string
Section: 27.4.3 [basic.string] Status: C++14 Submitter: Howard Hinnant Opened: 2011-05-29 Last modified: 2016-11-12
Priority: Not Prioritized
View other active issues in [basic.string].
View all other issues in [basic.string].
View all issues with C++14 status.
Discussion:
The following inconsistencies regarding noexcept
for basic_string
are noted.
noexcept
:
void swap(basic_string& str);
But the global swap is marked noexcept
:
template<class charT, class traits, class Allocator>
void swap(basic_string<charT,traits,Allocator>& lhs,
basic_string<charT,traits,Allocator>& rhs) noexcept;
But only in the definition, not in the synopsis.
All comparison operators are markednoexcept
in their definitions, but not in the synopsis.
The compare function that takes a pointer:
int compare(const charT *s) const;
is not marked noexcept
. But some of the comparison functions which are marked noexcept
(only in their definition) are specified to call the throwing compare operator:
template<class charT, class traits, class Allocator> bool operator==(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs) noexcept;
Returns:
lhs.compare(rhs) == 0
.
All functions with a narrow contract should not be declared as noexcept
according to
the guidelines presented in n3279.
Among these narrow contract functions are the swap
functions (23.2.2 [container.requirements.general] p. 8)
and functions with non-NULL
const charT*
parameters.
[2011-06-08 Daniel provides wording]
[Bloomington, 2011]
Move to Ready
Proposed resolution:
This wording is relative to the FDIS. Both move-assignment operator and the moving assign
function are not touched by this issue, because they are handled separately by issue 2063.
Modify the header <string>
synopsis in 27.4 [string.classes] as
indicated (Rationale: Adding noexcept
to these specific overloads is in sync with
applying the same rule to specific overloads of the member functions find
, compare
, etc.
This approach deviates from that taken in n3279,
but seems more consistent given similar application for comparable member functions):
#include <initializer_list> namespace std { […] template<class charT, class traits, class Allocator> bool operator==(const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; […] template<class charT, class traits, class Allocator> bool operator!=(const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; […] template<class charT, class traits, class Allocator> bool operator<(const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; […] template<class charT, class traits, class Allocator> bool operator>(const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; […] template<class charT, class traits, class Allocator> bool operator<=(const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; […] template<class charT, class traits, class Allocator> bool operator>=(const basic_string<charT,traits,Allocator>& lhs, const basic_string<charT,traits,Allocator>& rhs) noexcept; […] }
Modify the class template basic_string
synopsis in 27.4.3 [basic.string] as
indicated (Remark 1: The noexcept
at the move-constructor is fine, because even for a
small-object optimization there is no problem here, because basic_string::value_type
is required to be a non-array POD as of 27.1 [strings.general] p1, Remark 2: This
proposal removes the noexcept
at single character overloads of find
, rfind
,
etc. because they are defined in terms of potentially allocating functions. It seems like
an additional issue to me to change the semantics in terms of non-allocating functions and
adding noexcept
instead):
namespace std { template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_string { public: […] // [string.ops], string operations: […] size_type find (charT c, size_type pos = 0) constnoexcept; […] size_type rfind(charT c, size_type pos = npos) constnoexcept; […] size_type find_first_of(charT c, size_type pos = 0) constnoexcept; […] size_type find_last_of (charT c, size_type pos = npos) constnoexcept; […] size_type find_first_not_of(charT c, size_type pos = 0) constnoexcept; […] size_type find_last_not_of (charT c, size_type pos = npos) constnoexcept; […] }; }
Modify 27.4.3.8.2 [string.find] before p5 and before p7 as indicated:
size_type find(const charT* s, size_type pos = 0) constnoexcept; […] size_type find(charT c, size_type pos = 0) constnoexcept;-7- Returns:
find(basic_string<charT,traits,Allocator>(1,c), pos)
.
Modify [string.rfind] before p7 as indicated:
size_type rfind(charT c, size_type pos = npos) constnoexcept;-7- Returns:
rfind(basic_string<charT,traits,Allocator>(1,c),pos)
.
Modify [string.find.first.of] before p7 as indicated:
size_type find_first_of(charT c, size_type pos = 0) constnoexcept;-7- Returns:
find_first_of(basic_string<charT,traits,Allocator>(1,c), pos)
.
Modify [string.find.last.of] before p7 as indicated:
size_type find_last_of(charT c, size_type pos = npos) constnoexcept;-7- Returns:
find_last_of(basic_string<charT,traits,Allocator>(1,c),pos)
.
Modify [string.find.first.not.of] before p7 as indicated:
size_type find_first_not_of(charT c, size_type pos = 0) constnoexcept;-7- Returns:
find_first_not_of(basic_string(1, c), pos)
.
Modify [string.find.last.not.of] before p7 as indicated:
size_type find_last_not_of(charT c, size_type pos = npos) constnoexcept;-7- Returns:
find_last_not_of(basic_string(1, c), pos)
.
Modify [string.operator==] before p2+p3 as indicated:
template<class charT, class traits, class Allocator> bool operator==(const charT* lhs, const basic_string<charT,traits,Allocator>& rhs)noexcept; […] template<class charT, class traits, class Allocator> bool operator==(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs)noexcept;
Modify [string.op!=] before p2+p3 as indicated:
template<class charT, class traits, class Allocator> bool operator!=(const charT* lhs, const basic_string<charT,traits,Allocator>& rhs)noexcept; […] template<class charT, class traits, class Allocator> bool operator!=(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs)noexcept;
Modify [string.op<] before p2+p3 as indicated:
template<class charT, class traits, class Allocator> bool operator<(const charT* lhs, const basic_string<charT,traits,Allocator>& rhs)noexcept; […] template<class charT, class traits, class Allocator> bool operator<(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs)noexcept;
Modify [string.op>] before p2+p3 as indicated:
template<class charT, class traits, class Allocator> bool operator>(const charT* lhs, const basic_string<charT,traits,Allocator>& rhs)noexcept; […] template<class charT, class traits, class Allocator> bool operator>(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs)noexcept;
Modify [string.op<=] before p2+p3 as indicated:
template<class charT, class traits, class Allocator> bool operator<=(const charT* lhs, const basic_string<charT,traits,Allocator>& rhs)noexcept; […] template<class charT, class traits, class Allocator> bool operator<=(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs)noexcept;
Modify [string.op>=] before p2+p3 as indicated:
template<class charT, class traits, class Allocator> bool operator>=(const charT* lhs, const basic_string<charT,traits,Allocator>& rhs)noexcept; […] template<class charT, class traits, class Allocator> bool operator>=(const basic_string<charT,traits,Allocator>& lhs, const charT* rhs)noexcept;
Modify 27.4.4.3 [string.special] as indicated (Remark: The change of the semantics guarantees as of 16.3.2.4 [structure.specifications] p4 that the "Throws: Nothing" element of member swap is implied):
template<class charT, class traits, class Allocator> void swap(basic_string<charT,traits,Allocator>& lhs, basic_string<charT,traits,Allocator>& rhs)noexcept;-1- Effects: Equivalent to
lhs.swap(rhs);