This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++14 status.

### 2064. More `noexcept` issues in `basic_string`

Section: 23.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.

Member swap is not marked `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 marked `noexcept` 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 (24.2.2.1 [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.

1. Modify the header `<string>` synopsis in 23.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;
   >       […]
   >     }

2. Modify the class template `basic_string` synopsis in 23.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 23.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) const noexcept;
   >         […]
   >         size_type rfind(charT c, size_type pos = npos) const noexcept;
   >         […]
   >         size_type find_first_of(charT c, size_type pos = 0) const noexcept;
   >         […]
   >         size_type find_last_of (charT c, size_type pos = npos) const noexcept;
   >         […]
   >         size_type find_first_not_of(charT c, size_type pos = 0) const noexcept;
   >         […]
   >         size_type find_last_not_of (charT c, size_type pos = npos) const noexcept;
   >         […]
   >       };
   >     }

3. Modify 23.4.3.8.2 [string.find] before p5 and before p7 as indicated:

   >     size_type find(const charT* s, size_type pos = 0) const noexcept;
   >     […]
   >     size_type find(charT c, size_type pos = 0) const noexcept;

   > > -7- Returns: `find(basic_string<charT,traits,Allocator>(1,c), pos)`.

4. Modify 99 [string.rfind] before p7 as indicated:

   >     size_type rfind(charT c, size_type pos = npos) const noexcept;

   > > -7- Returns: `rfind(basic_string<charT,traits,Allocator>(1,c),pos)`.

5. Modify 99 [string.find.first.of] before p7 as indicated:

   >     size_type find_first_of(charT c, size_type pos = 0) const noexcept;

   > > -7- Returns: `find_first_of(basic_string<charT,traits,Allocator>(1,c), pos)`.

6. Modify 99 [string.find.last.of] before p7 as indicated:

   >     size_type find_last_of(charT c, size_type pos = npos) const noexcept;

   > > -7- Returns: `find_last_of(basic_string<charT,traits,Allocator>(1,c),pos)`.

7. Modify 99 [string.find.first.not.of] before p7 as indicated:

   >     size_type find_first_not_of(charT c, size_type pos = 0) const noexcept;

   > > -7- Returns: `find_first_not_of(basic_string(1, c), pos)`.

8. Modify 99 [string.find.last.not.of] before p7 as indicated:

   >     size_type find_last_not_of(charT c, size_type pos = npos) const noexcept;

   > > -7- Returns: `find_last_not_of(basic_string(1, c), pos)`.

9. 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;

10. 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;

11. 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;

12. 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;

13. 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;

14. 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;

15. Modify 23.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);`