Title
More noexcept issues in basic_string
Status
c++14
Section
[basic.string]
Submitter
Howard Hinnant

Created on 2011-05-29.00:00:00, last changed 2014-02-20.13:20:35.

Messages

Date: 2011-08-16.12:46:19

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 [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 [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 [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 [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 [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 [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 [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 [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 [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 [string.special] as indicated (Remark: The change of the semantics guarantees as of [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);

Date: 2011-08-16.12:46:19

[ Bloomington, 2011 ]

Move to Ready

Date: 2011-06-08.00:00:00

[ 2011-06-08 Daniel provides wording ]

Date: 2011-05-29.00:00:00

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 ([container.requirements.general] p. 8) and functions with non-NULL const charT* parameters.

History
Date User Action Args
2014-02-20 13:20:35adminsetstatus: wp -> c++14
2012-02-12 18:36:43adminsetstatus: voting -> wp
2012-02-09 04:07:48adminsetstatus: ready -> voting
2011-08-16 12:46:19adminsetmessages: + msg5844
2011-08-16 12:46:19adminsetstatus: new -> ready
2011-06-08 18:31:14adminsetmessages: + msg5812
2011-06-08 18:31:14adminsetmessages: + msg5811
2011-05-29 00:00:00admincreate