N3263 - More on noexcept for the Containers Library (revision)
Document number: N3263=11-0033
Date: 2011-03-25
J. Daniel Garcia
Project: Programming Language C++, Library Working Group
Reply To: josedaniel.garcia@uc3m.es

N3263 - More on noexcept for the Containers Library (revision)

This paper studies possible changes to the Containers Library to make broad use of noexcept. The paper addresses National Body comments CH 16 and GB 60.

Changes in this paper are restricted to chapter 23 (containers library).

All changes in this paper are relative to N3242.

Discussion

After discussion in Library Working Group of guidelines for applying noexcept to the standard library (N3248), this paper has been revised to apply noexcept accordingly to those guidelines

Acknowledgments

A previous version (N3187) was revised by Daniel Krügler. The following people made very useful suggestions: Francisco Palomo, Martin Sebor, and Daniel Krügler.

Proposed Wording

23.3 Sequence containers [sequences]

After p. 1
namespace std {
  #include <initializer_list>

...
  template <class T, size_t N >
    void swap(array<T,N>& x, array<T,N>& y)noexcept(noexcept(x.swap(y)));
...
}

23.3.2 Class template array [array]

After p. 3
namespace std {
  template <class T, size_t N >
  struct array {
...

    // No explicit construct/copy/destroy for aggregate type
...
    void swap(array&) noexcept(noexcept(swap(declval<T&>(), declval<T&>())));

    // iterators:
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // capacity:
    constexpr size_type size() noexcept;
    constexpr size_type max_size() noexcept;
    constexpr bool empty() noexcept;

    // element access:
    reference operator[](size_type n);
    const_reference operator[](size_type n) const;
    const_reference at(size_type n) const;
    reference at(size_type n);
    reference front();
    const_reference front() const;
    reference back();
    const_reference back() const;
    T * data() noexcept;
    const T * data() const noexcept;
  };
}

23.3.2.3 array specialized algorithms [array.special]

Before p. 1
template <class T, size_t N> void swap(array<T,N>& x, array<T,N>& y)
  noexcept(noexcept(x.swap(y)));

23.3.2.4 array::size [array.size]

Before p. 1
template <class T, size_t N> constexpr size_type array<T,N>::size() noexcept;

23.3.2.5 array::data [array.data]

Before p. 1
T *data() noexcept;
const T *data() const noexcept;

23.3.2.7 array::swap [array.swap]

Before p. 1
void swap(array& y) noexcept(noexcept(swap(declval<T&>(), declval<T&>())));

23.3.2.8 Zero sized arrays [array.zero]

After p.3

? Member function swap() shall have a noexcept-specification which is equivalent to noexcept(true).

23.3.3 Class template deque [deque]

After p. 2
namespace std {
  template <class T, class Allocator = allocator<T> >
  class deque {
    public:
...
    allocator_type get_allocator() const noexcept;
    
    // iterators:
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;
    
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;
    
    // 23.3.2.2 capacity:
    size_type size() const noexcept;
    size_type max_size() const noexcept;
    void resize(size_type sz);
    void resize(size_type sz, const T& c);
    void shrink_to_fit();
    bool empty() const noexcept;
    
...
    
    void swap(deque<T,Allocator>&);
    void clear() noexcept;
  };

...
}

23.3.4 Class template forward_list [forwardlist]

After p. 3
namespace std {
  template <class T, class Allocator = allocator<T> >
  class forward_list {
    ...
    allocator_type get_allocator() const noexcept;
    ...
    // 23.3.3.2 iterators:
    iterator before_begin() noexcept;
    const_iterator before_begin() const noexcept;
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;

    const_iterator cbegin() const noexcept;
    const_iterator cbefore_begin() const noexcept;
    const_iterator cend() const noexcept;

    // capacity:
    bool empty() const noexcept;
    size_type max_size() const noexcept;

    ...
    void swap(forward_list<T,Allocator>&);

    void resize(size_type sz);
    void resize(size_type sz, value_type c);
    void clear() noexcept;
    ...
  };

...
}

23.3.4.3 forward_list iterators [forwardlist.iter]

Before p. 1
iterator before_begin() noexcept;
const_iterator before_begin() const noexcept;
const_iterator cbefore_begin() const noexcept;

23.3.4.5 forward_list modifiers [forwardlist.modifiers]

After p. 27
void clear() noexcept;

23.3.5 Class template list [list]

After p. 3
namespace std {
  template <class T, class Allocator = allocator<T> >
  class list {
  public:
...
    allocator_type get_allocator() const noexcept;

    // iterators:
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // 23.3.4.2 capacity:
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;
    void resize(size_type sz);
    void resize(size_type sz, const T& c);
...
    // 23.3.4.3 modifiers:
...
    void swap(list<T,Allocator>&);
    void clear() noexcept;
...
  };
...

}

23.3.6 Class template vector [vector]

After p. 3
namespace std {
  template <class T, class Allocator = allocator<T> >
  class vector {
    public:
...
    allocator_type get_allocator() const noexcept;

    // iterators:
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // 23.4.1.2 capacity:
    size_type size() const noexcept;
    size_type max_size() const noexcept;
    void resize(size_type sz);
    void resize(size_type sz, const T& c);
    size_type capacity() const noexcept;
    bool empty() const noexcept;
    void reserve(size_type n);
    void shrink_to_fit();

...
    void swap(vector<T,Allocator>&);
    void clear() noexcept;
  };
...
  // specialized algorithms:
  template <class T, class Allocator>
    void swap(vector<T,Allocator>& x, vector<T,Allocator>& y);

}

23.3.6.3 vector capacity [vector.capacity]

Before p. 1
size_type capacity() const noexcept;

23.3.8 Class vector<bool> overview [vector.bool]

After p. 1
namespace std {
  template <class Allocator> class vector<bool, Allocator> {
  public:
...
    // bit reference:
    class reference {
      friend class vector;
      reference() noexcept;
    public:
      ~reference();
      operator bool() const noexcept;
      reference& operator=(const bool x) noexcept;
      reference& operator=(const reference& x) noexcept;
      void flip() noexcept; // flips the bit
    };

...
    allocator_type get_allocator() const noexcept;

    // iterators:
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // capacity:
    size_type size() const noexcept;
    size_type max_size() const noexcept;
    void resize(size_type sz, bool c = false);
    size_type capacity() const noexcept;
    bool empty() const noexcept;
    void reserve(size_type n);
    void shrink_to_fit();
...
    // modifiers:
...
    void swap(vector<bool,Allocator>&);
    static void swap(reference x, reference y) noexcept;
    void flip() noexcept; // flips all bits
    void clear() noexcept;
  };
After p. 4
void flip() noexcept;
After p. 5
static void swap(reference x, reference y) noexcept;

23.4.5 Class template map [map]

After p. 2
namespace std {
  template <class Key, class T, class Compare = less<Key>,
            class Allocator = allocator<pair<const Key, T> > >
  class map {
  public:
...
    // 23.6.1.1 construct/copy/destroy:
...
    allocator_type get_allocator() const noexcept;

    // iterators:
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;

    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // capacity:
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;
...
// modifiers:
...
    void clear() noexcept;
...
  };
...
}

23.4.5 Class template multimap [multimap]

After p. 2
namespace std {
  template <class Key, class T, class Compare = less<Key>,
            class Allocator = allocator<pair<const Key, T> > >
  class multimap {
  public:
...
    allocator_type get_allocator() const noexcept;

    // iterators:
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;

    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // capacity:
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;
...
    // modifiers:
...
    void clear() noexcept;
...
  };

...
}

23.4.6 Class template set [set]

After p. 2
namespace std {
  template <class Key, class Compare = less<Key>,
            class Allocator = allocator<Key> >
  class set {
  public:
...
    allocator_type get_allocator() const noexcept;

    // iterators:
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;

    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // capacity:
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // modifiers:
...
    void clear() noexcept;
...
  };
...
}

23.4.7 Class template multiset [multiset]

After p. 2
namespace std {
  template <class Key, class Compare = less<Key>,
            class Allocator = allocator<Key> >
  class multiset {
  public:
...
    allocator_type get_allocator() const noexcept;

    // iterators:
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;

    reverse_iterator rbegin() noexcept;
    const_reverse_iterator rbegin() const noexcept;
    reverse_iterator rend() noexcept;
    const_reverse_iterator rend() const noexcept;

    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;
    const_reverse_iterator crbegin() const noexcept;
    const_reverse_iterator crend() const noexcept;

    // capacity:
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // modifiers:
...
    void clear() noexcept;
...
  };
...
}

23.5.4 Class template unordered_map [unord.map]

After p. 3
namespace std {
template <class Key,
          class T,
          class Hash = hash<Key>,
          class Pred = std::equal_to<Key>,
          class Alloc = std::allocator<std::pair<const Key, T> > >
  class unordered_map
  {
  public:
...
    allocator_type get_allocator() const noexcept;

    // size and capacity
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // iterators
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;

    // modifiers
...
    void clear() noexcept;
...
    // bucket interface
    size_type bucket_count() const noexcept;
    size_type max_bucket_count() const noexcept;
...
    // hash policy
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
...
  };
...
}

23.5.5 Class template unordered_multimap [unord.multimap]

After p. 3
namespace std {
  template <class Key,
            class T,
            class Hash = hash<Key>,
            class Pred = std::equal_to<Key>,
            class Alloc = std::allocator<std::pair<const Key, T> > >
  class unordered_multimap
  {
  public:
...
    allocator_type get_allocator() const noexcept;

    // size and capacity
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // iterators
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;

    // modifiers
...
    void clear() noexcept;
...
    // bucket interface
    size_type bucket_count() const noexcept;
    size_type max_bucket_count() const noexcept;
...
    // hash policy
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
...
  };
...
}

23.5.6 Class template unordered_set [unord.set]

After p. 3
namespace std {
  template <class Key,
            class Hash = hash<Key>,
            class Pred = std::equal_to<Key>,
            class Alloc = std::allocator<Key> >
   class unordered_set
  {
  public:
...
    allocator_type get_allocator() const noexcept;

    // size and capacity
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // iterators
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;

    // modifiers
...
    void clear() noexcept;
...
    // bucket interface
    size_type bucket_count() const noexcept;
    size_type max_bucket_count() const noexcept;
...
    // hash policy
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
...
  };

}

23.5.7 Class template unordered_multiset [unord.multiset]

After p. 3
namespace std {
  template <class Key,
            class Hash = hash<Key>,
            class Pred = std::equal_to<Key>,
            class Alloc = std::allocator<Key> >
  class unordered_multiset
  {
  public:
...
    allocator_type get_allocator() const noexcept;

    // size and capacity
    bool empty() const noexcept;
    size_type size() const noexcept;
    size_type max_size() const noexcept;

    // iterators
    iterator begin() noexcept;
    const_iterator begin() const noexcept;
    iterator end() noexcept;
    const_iterator end() const noexcept;
    const_iterator cbegin() const noexcept;
    const_iterator cend() const noexcept;

    // modifiers
...
    void clear() noexcept;
...
    // bucket interface
    size_type bucket_count() const noexcept;
    size_type max_bucket_count() const noexcept;
...
    // hash policy
    float load_factor() const noexcept;
    float max_load_factor() const noexcept;
...
  };
...
}

23.6.2 Header synopsis [queue.syn]

...
template <class T, class AllocatorContainer>
void swap(queue<T, Container>& x, queue<T, Container>& y) noexcept(noexcept(x.swap(y)));
template <class T, class Container, class Compare>
void swap(priority_queue<T, Container, Compare>& x, priority_queue<T, Container, Compare>& y) noexcept(noexcept(x.swap(y)));
...

23.6.3.1 queue definition [queue.defn]

namespace std {
  template <class T, class Container = deque<T> >
  class queue {
  public:
...
    queue(queue&& q) noexcept(see below);
...
    queue& operator=(queue&& q) noexcept(see below);
...    
    void swap(queue& q) noexcept(noexcept(swap(c,q.c)))
      { using std::swap; swap(c, q.c); }
  };
...
  template <class T, class Container>
    void swap(queue<T, Container>& x, queue<T, Container>& y)
      noexcept(noexcept(x.swap(y)));
...
}

23.6.3.2 queue constructors [queue.cons]

After p. 2
queue(queue&& q) noexcept(see below);

Remarks: The expression inside noexcept is equivalent to:

  is_nothrow_constructible<Container>::value
After p. 3
queue& operator=(queue&& q) noexcept(see below);

Remarks: The expression inside noexcept is equivalent to:

  is_nothrow_move_assignable<Container>::value

23.6.3.5 queue specialized algorithms [queue.special]

Before p. 1
template <class T, class Container>
  void swap(queue<T, Container>& x, queue<T, Container>& y)noexcept(noexcept(x.swap(y)));

23.6.4 Class template priority_queue [priority.queue]

After p. 1
namespace std {
  template <class T, class Container = vector<T>,
    class Compare = less<typename Container::value_type> >
  class priority_queue {
  public:
...
    priority_queue(priority_queue&&) noexcept(see below);
...
    priority_queue& operator=(priority_queue&&) noexcept(see below);
...
    void swap(priority_queue& q) noexcept(
        noexcept(swap(c, q.c)) && 
        noexcept(swap(comp, q.comp)))
      { using std::swap; swap(c, q.c); swap(comp, q.comp); }
  };
  // no equality is provided
  template <class T, class Container, class Compare>
    void swap(priority_queue<T, Container, Compare>& x, priority_queue<T, Container, Compare>& y)
      noexcept(noexcept(x.swap(y)));
...
}

23.6.4.1 priority_queue constructors [priqueue.cons]

After p. 4
priority_queue(priority_queue&& q) noexcept(see below);

Remarks: The expression inside noexcept is equivalent to:

  is_nothrow_move_constructible<Compare>::value &&
  is_nothrow_move_constructible<Container>::value
After p. 5
priority_queue& operator=(priority_queue&& q) noexcept(see below);

Remarks: The expression inside noexcept is equivalent to:

  is_nothrow_move_assignable<Compare>::value &&
  is_nothrow_move_assignable<Container>::value

23.6.4.4 priority_queue specialized algorithms [priqueue.special]

Before p. 1
template <class T, class Container, Compare>
  void swap(priority_queue<T, Container, Compare>& x, priority_queue<T, Container, Compare>& y)
    noexcept(noexcept(x.swap(y)));

23.6.5.1 Header synopsis [stack.syn]

...
  template <class T, class Container>
    void swap(stack<T, Container>& x, stack<T, Container>& y) noexcept(noexcept(x.swap(y)));
}

23.6.5.2 stack definition [stack.defn]

namespace std {
  template <class T, class Container = deque<T> >
  class stack {
  public:
...
    explicit stack(Container&& = Container());
    stack(stack&&s) noexcept(see below);
...
    stack& operator=(stack&& s) noexcept(see below);
...
    void swap(stack& s) noexcept(noexcept(swap(c, s.c))) { using std::swap; swap(c, s.c); }
  };
...
  template <class T, class Container, class Alloc>
    struct uses_allocator<stack<T, Container>, Alloc>
      : uses_allocator<Container, Alloc>::type { };
}

23.6.5.3 stack constructors [stack.cons]

Before p. 1
stack(stack&& s) noexcept(see below);

Remarks: The expression inside noexcept is equivalent to:

  is_nothrow_move_constructible<Container>::value
After p. 1
stack& operator=(stack&& s) noexcept(see below);

Remarks: The expression inside noexcept is equivalent to:

  is_nothrow_move_assignable<Container>::value

23.6.5.6 stack specialized algorithms [stack.special]

Before p. 1
template <class T, class Container>
  void swap(stack<T, Container>& x, stack<T, Container>& y)noexcept(noexcept(x.swap(y)));