2250. Follow-up On Library Issue 2207

Section: 23.9.2.1 [bitset.cons], 23.9.2.2 [bitset.members], 24.3.2.2 [string.cons], 24.3.2.6 [string.modifiers], 24.3.2.7 [string.ops] Status: C++17 Submitter: Frank Birbacher Opened: 2013-04-18 Last modified: 2017-07-30

Priority: 3

View all other issues in [bitset.cons].

View all issues with C++17 status.

Discussion:

Similar to LWG 2207 there are several other places where the "Requires" clause precludes the "Throws" condition. Searching for the out_of_range exception to be thrown, the following have been found (based on the working draft N3485):

  1. 23.9.2.1 [bitset.cons] p3+4

  2. 23.9.2.2 [bitset.members] p13+14 (set)

  3. 23.9.2.2 [bitset.members] p19+20 (reset)

  4. 23.9.2.2 [bitset.members] p27+28 (flip)

  5. 23.9.2.2 [bitset.members] p41+42 (test)

  6. 24.3.2.2 [string.cons] p3+4

  7. 24.3.2.6.2 [string.append] p3+4

  8. 24.3.2.6.3 [string.assign] p4+5

  9. 24.3.2.6.4 [string.insert] p1+2, p5+6, p9+10 (partially)

  10. 24.3.2.6.5 [string.erase] p1+2

  11. 24.3.2.6.6 [string.replace] p1+2, p5+6, p9+10 (partially)

  12. 24.3.2.6.7 [string.copy] p1+2

  13. 24.3.2.7.8 [string.substr] p1+2

[2013-10-15: Daniel provides wording]

In addition to the examples mentioned in the discussion, a similar defect exists for thread's join() and detach functions (see 33.3.2.5 [thread.thread.member]). The suggested wording applies a similar fix for these as well.

[2015-05, Lenexa]

STL : likes it
DK : does it change behavior?
Multiple : no
Move to ready? Unanimous

Proposed resolution:

This wording is relative to N3936.

  1. Modify 23.9.2.1 [bitset.cons] as indicated: [Editorial comment: The wording form used to ammend the Throws element is borrowed from a similar style used in 24.3.2.6.6 [string.replace] p10]

    template <class charT, class traits, class Allocator>
    explicit
    bitset(const basic_string<charT, traits, Allocator>& str,
           typename basic_string<charT, traits, Allocator>::size_type pos = 0,
           typename basic_string<charT, traits, Allocator>::size_type n =
             basic_string<charT, traits, Allocator>::npos,
             charT zero = charT('0'), charT one = charT('1'));
    

    -3- Requires: pos <= str.size().

    -4- Throws: out_of_range if pos > str.size() or invalid_argument if an invalid character is found (see below).

    -5- Effects: Determines the effective length rlen of the initializing string as the smaller of n and str.size() - pos.

    The function then throws invalid_argument if any of the rlen characters in str beginning at position pos is other than zero or one. The function uses traits::eq() to compare the character values.

    […]

  2. Modify 23.9.2.2 [bitset.members] as indicated:

    bitset<N>& set(size_t pos, bool val = true);
    

    -13- Requires: pos is valid

    -14- Throws: out_of_range if pos does not correspond to a valid bit position.

    […]

    bitset<N>& reset(size_t pos);
    

    -19- Requires: pos is valid

    -20- Throws: out_of_range if pos does not correspond to a valid bit position.

    […]

    bitset<N>& flip(size_t pos);
    

    -27- Requires: pos is valid

    -28- Throws: out_of_range if pos does not correspond to a valid bit position.

    […]

    bool test(size_t pos) const;
    

    -41- Requires: pos is valid

    -42- Throws: out_of_range if pos does not correspond to a valid bit position.

    […]

  3. Modify 24.3.2.2 [string.cons] as indicated:

    basic_string(const basic_string& str,
                 size_type pos, size_type n = npos,
                 const Allocator& a = Allocator());
    

    -3- Requires: pos <= str.size()

    -4- Throws: out_of_range if pos > str.size().

  4. Modify 24.3.2.4 [string.capacity] as indicated:

    void resize(size_type n, charT c);
    

    -6- Requires: n <= max_size()

    -7- Throws: length_error if n > max_size().

  5. Modify 24.3.2.6.2 [string.append] as indicated:

    basic_string&
      append(const basic_string& str, size_type pos, size_type n = npos);
    

    -3- Requires: pos <= str.size()

    -4- Throws: out_of_range if pos > str.size().

  6. Modify 24.3.2.6.3 [string.assign] as indicated:

    basic_string&
      assign(const basic_string& str, size_type pos, 
             size_type n = npos);
    

    -5- Requires: pos <= str.size()

    -6- Throws: out_of_range if pos > str.size().

  7. Modify 24.3.2.6.4 [string.insert] as indicated: [Editorial note: The first change suggestion is also a bug fix of the current wording, because (a) the function has parameter pos1 but the semantics refers to pos and (b) it is possible that this function can throw length_error, see p10]

    basic_string&
      insert(size_type pos1, const basic_string& str);
    

    -1- Requires: pos <= size().

    -2- Throws: out_of_range if pos > size().

    -3- Effects: CallsEquivalent to: return insert(pos, str.data(), str.size());.

    -4- Returns: *this.

    basic_string&
      insert(size_type pos1, const basic_string& str,
             size_type pos2, size_type n = npos);
    

    -5- Requires: pos1 <= size() and pos2 <= str.size().

    -6- Throws: out_of_range if pos1 > size() or pos2 > str.size().

    […]

    basic_string&
      insert(size_type pos, const charT* s, size_type n);
    

    -9- Requires: s points to an array of at least n elements of charT and pos <= size().

    -10- Throws: out_of_range if pos > size() or length_error if size() + n > max_size().

    […]

    basic_string&
      insert(size_type pos, const charT* s);
    

    -13- Requires: pos <= size() and s points to an array of at least traits::length(s) + 1 elements of charT.

    -14- Effects: Equivalent to return insert(pos, s, traits::length(s));.

    -15- Returns: *this.

  8. Modify 24.3.2.6.5 [string.erase] as indicated:

    basic_string& erase(size_type pos = 0, size_type n = npos);
    

    -1- Requires: pos <= size()

    -2- Throws: out_of_range if pos > size().

    […]

  9. Modify 24.3.2.6.6 [string.replace] as indicated: [Editorial note: The first change suggestion is also a bug fix of the current wording, because it is possible that this function can throw length_error, see p10]

    basic_string&
      replace(size_type pos1, size_type n1,
              const basic_string& str);
    

    -1- Requires: pos1 <= size().

    -2- Throws: out_of_range if pos1 > size().

    -3- Effects: CallsEquivalent to return replace(pos1, n1, str.data(), str.size());.

    -4- Returns: *this.

    basic_string&
      replace(size_type pos1, size_type n1,
              const basic_string& str,
              size_type pos2, size_type n = npos);
    

    -5- Requires: pos1 <= size() and pos2 <= str.size().

    -6- Throws: out_of_range if pos1 > size() or pos2 > str.size().

    […]

    basic_string&
      replace(size_type pos1, size_type n1, const charT* s, size_type n2);
    

    -9- Requires: pos1 <= size() and s points to an array of at least n2 elements of charT.

    -10- Throws: out_of_range if pos1 > size() or length_error if the length of the resulting string would exceed max_size() (see below).

    […]

    basic_string&
      replace(size_type pos, size_type n, const charT* s);
    

    -13- Requires: pos <= size() and s points to an array of at least traits::length(s) + 1 elements of charT.

    -14- Effects: Equivalent to return replace(pos, n, s, traits::length(s));.

    -15- Returns: *this.

  10. Modify 24.3.2.6.7 [string.copy] as indicated:

    size_type copy(charT* s, size_type n, size_type pos = 0) const;
    

    -1- Requires: pos <= size()

    -2- Throws: out_of_range if pos > size().

    […]

  11. Modify 24.3.2.7.8 [string.substr] as indicated:

    basic_string substr(size_type pos = 0, size_type n = npos) const;
    

    -1- Requires: pos <= size()

    -2- Throws: out_of_range if pos > size().

    […]

  12. Modify 33.3.2.5 [thread.thread.member] as indicated:

    void join();
    

    -3- Requires: joinable() is true.

    […]

    -7- Throws: system_error when an exception is required (30.2.2).

    -8- Error conditions:

    • […]

    • invalid_argument — if the thread is not joinable.

    void detach();
    

    -9- Requires: joinable() is true.

    […]

    -12- Throws: system_error when an exception is required (30.2.2).

    -13- Error conditions:

    • […]

    • invalid_argument — if the thread is not joinable.