Title
Member swap undefined for most containers
Status
c++11
Section
[containers]
Submitter
Alisdair Meredith

Created on 2008-01-14.00:00:00 last changed 162 months ago

Messages

Date: 2010-10-21.18:28:33

[ Note to the editor: Paragraph 2 starts with a sentence fragment, clearly from an editing or source-control error. ]

Modify [associative.reqmts.except] as follows:

23.2.4.1 Exception safety guarantees [associative.reqmts.except]

For associative containers, no clear() function throws an exception. erase(k) does not throw an exception unless that exception is thrown by the container's PredCompare object (if any).

For associative containers, if an exception is thrown by any operation from within an insert() function inserting a single element, the insert() function has no effect.

For associative containers, no swap function throws an exception unless that exception is thrown by the copy constructor or copy assignment operatorswap of the container's PredCompare object (if any).

Modify [unord.req.except], paragraph 3 as follows:

For unordered associative containers, no swap function throws an exception unless that exception is thrown by the copy constructor or copy assignment operatorswap of the container's Hash or Pred object (if any).

Modify section [array.special]:

array specialized algorithms [array.special]

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

Effects: swap_ranges(x.begin(), x.end(), y.begin() );x.swap(y);

Add a new section after [array.fill] (Note to the editor: array::fill make use of a concept requirement that must be removed or changed to text.):

array::swap [array.swap]

void swap(array& y);

Effects: swap_ranges(this->begin(), this->end(), y.begin() );

Throws: Nothing unless one of the element-wise swap calls throws an exception.

[Note: Unlike other containers' swap functions, array::swap takes linear, not constant, time, may exit via an exception, and does not cause iterators to become associated with the other container. — end note]

Insert a new paragraph just after [container.adaptors]/1:

For container adaptors, no swap function throws an exception unless that exception is thrown by the swap of the adaptor's Container or Compare object (if any).

Date: 2010-10-21.18:28:33

[ This resolution is based on the September 2009 WP, N2960, except that it assumes that N2982 and issues 883 and 1232 have already been applied. Note in particular that Table 91 in N2960 is refered to as Table 90 because N2982 removed the old Table 90. This resolution also addresses issue 431. ]

In [container.requirements.general], replace the a.swap(b) row in table 90, "container requirements" (was table 91 before the application of N2982 to the WP):

a.swap(b) void     swap(a,b)Exchange the contents of a and b. (Note A)
swap(a,b) void     a.swap(b) (Note A)

Modify the notes immediately following Table 90 in [container.requirements.general] as follows (The wording below is after the application of N2982 to N2960. The editor might also want to combine Notes A and B into one.):

Notes: the algorithms swap(), equal() and lexicographical_compare() are defined in Clause 25. Those entries marked "(Note A)" or "(Note B)" should have linear complexity for array and constant complexity for all other standard containers.

In [container.requirements.general], before paragraph 8, add:

The expression a.swap(b), for containers a and b of a standard container type other than array, exchanges the values of a and b without invoking any move, copy, or swap operations on the individual container elements. Any Compare, Pred, or Hash function objects belonging to a and b shall be swappable and are exchanged by unqualified calls to non-member swap. If allocator_traits<allocator_type>::propagate_on_container_swap::value == true, then the allocators of a and b are also exchanged using an unqualified call to non-member swap. Otherwise, the behavior is undefined unless a.get_allocator() == b.get_allocator(). Each iterator refering to an element in one container before the swap shall refer to the same element in the other container after the swap. It is unspecified whether an iterator with value a.end() before the swap will have value b.end() after the swap. In addition to being available via inclusion of the <utility> header, the swap function template in [alg.swap] is also available within the definition of every standard container's swap function.

Date: 2010-10-21.18:28:33

[ 2010 Pittsburgh: Ready for Pittsburgh. ]

Date: 2009-10-30.00:00:00

[ 2009-10-30 Pablo and Daniel updated wording. ]

Date: 2009-10-26.00:00:00

[ 2009-10-26 Pablo updated wording. Here is the wording he replaced: ]

  1. Add a new Throws clause just after [allocator.propagation.map]/5:

    static void swap(Alloc& a, Alloc& b);
    

    Effects: [..]

    Throws: Nothing.

    This exception requirement is added, such that it's combination with the general container requirements of N2723 [container.requirements.general]/9 make it unambiguously clear that the following descriptions of "swaps the allocators" have the following meaning: (a) This swap is done by calling allocator_propagation_map<allocator_type>::swap and (b) This allocator swap does never propagate an exception
  2. Change [associative.reqmts.except]/3 as indicated:

    For associative containers, no swap function throws an exception unless that exception is thrown by the copy constructor or copy assignment operator swap of the container's Pred objects (if any).

  3. Change [unord.req.except]/3 as indicated:

    For unordered associative containers, no swap function throws an exception unless that exception is thrown by the copy constructor or copy assignment operator swap of the container's Hash or Pred objects, respectively (if any).

  4. Insert a new paragraph just after [sequences]/1:

    In addition to being available via inclusion of the <algorithm> header, the swap function templates in [alg.swap] are also available when the header <queue> is included.

    There is a new issue in process that will suggest a minimum header for swap and move. If this one is provided, this text can be removed and the header dependency should be added to <queue>
  5. Add one further clause at the end of [array.special]:

    This part is added, because otherwise array::swap would otherwise contradict the general contract of [container.requirements.general] p. 10 b. 5

    Throws: Nothing, unless one of the element-wise swap calls throws an exception.

    1. In [deque], class template deque synopsis change as indicated:

      void swap(deque<T,Alloc>&);
      
    2. At the end of [deque.modifiers] add as indicated:

      void swap(deque& x);
      

      Effects: Exchanges the contents and swaps the allocators of *this with that of x.

      Complexity: Constant time.

    1. In [forwardlist], class template forward_list synopsis change as indicated:

      void swap(forward_list<T,Allocator>&);
      
    2. At the end of [forwardlist.modifiers] add as indicated:

      void swap(forward_list& x);
      

      Effects: Exchanges the contents and swaps the allocators of *this with that of x.

      Complexity: Constant time.

    1. In [list], class template list synopsis change as indicated:

      void swap(list<T,Allocator>&);
      
    2. At the end of [list.modifiers] add as indicated:

      void swap(list& x);
      

      Effects: Exchanges the contents and swaps the allocators of *this with that of x.

      Complexity: Constant time.

  6. At the end of [priqueue.members] add a new prototype description:

    void swap(priority_queue& q);
    

    Requires: Compare shall satisfy the Swappable requirements ([swappable]).

    This requirement is added to ensure that even a user defined swap which is found by ADL for Compare satisfies the Swappable requirements

    Effects: this->c.swap(q.c); swap(this->comp, q.comp);

    Throws: What and if c.swap(q.c) and swap(comp, q.comp) throws.

    This part is added, because otherwise priority_queue::swap would otherwise contradict the general contract of [container.requirements.general] p. 10 b. 5
    1. In [vector], class template vector synopsis change as indicated:

      void swap(vector<T,Allocator>&);
      
    2. Change [vector.capacity] p. 8 as indicated:

      void swap(vector<T,Allocator>& x);
      

      Effects: Exchanges the contents and capacity() and swaps the allocators of *this with that of x.

  7. Insert a new paragraph just before [associative]/1:

    In addition to being available via inclusion of the <algorithm> header, the swap function templates in [alg.swap] are also available when any of the headers <map> or <set> are included.

    1. In [map], class template map synopsis change as indicated:

      void swap(map<Key,T,Compare,Allocator>&);
      
    2. At the end of [map.modifiers] add as indicated:

      void swap(map& x);
      

      Requires: Compare shall satisfy the Swappable requirements ([swappable]).

      This requirement is added to ensure that even a user defined swap which is found by ADL for Compare satisfies the Swappable requirements

      Effects: Exchanges the contents and swaps the allocators of *this with that of x, followed by an unqualified swap of the comparison objects of *this and x.

      Complexity: Constant time

    1. In [multimap], class template multimap synopsis change as indicated:

      void swap(multimap<Key,T,Compare,Allocator>&);
      
    2. At the end of [multimap.modifiers] add as indicated:

      void swap(multimap& x);
      

      Requires: Compare shall satisfy the Swappable requirements ([swappable]).

      Effects: Exchanges the contents and swaps the allocators of *this with that of x, followed by an unqualified swap of the comparison objects of *this and x.

      Complexity: Constant time

    1. In [set], class template set synopsis change as indicated:

      void swap(set<Key,Compare,Allocator>&);
      
    2. After section [set.cons] add a new section set modifiers [set.modifiers] and add the following paragraphs:

      void swap(set& x);
      

      Requires: Compare shall satisfy the Swappable requirements ([swappable]).

      Effects: Exchanges the contents and swaps the allocators of *this with that of x, followed by an unqualified swap of the comparison objects of *this and x.

      Complexity: Constant time

    1. In [multiset], class template multiset synosis, change as indicated:

      void swap(multiset<Key,Compare,Allocator>&);
      
    2. After section [multiset.cons] add a new section multiset modifiers [multiset.modifiers] and add the following paragraphs:

      void swap(multiset& x);
      

      Requires: Compare shall satisfy the Swappable requirements ([swappable]).

      Effects: Exchanges the contents and swaps the allocators of *this with that of x, followed by an unqualified swap of the comparison objects of *this and x.

      Complexity: Constant time

  8. Insert a new paragraph just before [unord] p. 1:

    In addition to being available via inclusion of the <algorithm> header, the swap function templates in [alg.swap] are also available when any of the headers <unordered_map> or <unordered_set> are included.

  9. After section [unord.map.elem] add a new section unordered_map modifiers [unord.map.modifiers] and add the following paragraphs:

    void swap(unordered_map& x);
    

    Requires: Hash and Pred shall satisfy the Swappable requirements ([swappable]).

    This requirement is added to ensure that even a user defined swap which is found by ADL for Hash and Pred satisfies the Swappable requirements

    Effects: Exchanges the contents and hash policy and swaps the allocators of *this with that of x, followed by an unqualified swap of the Pred objects and an unqualified swap of the Hash objects of *this and x.

    Complexity: Constant time

  10. After section [unord.multimap.cnstr] add a new section unordered_multimap modifiers [unord.multimap.modifiers] and add the following paragraphs:

    void swap(unordered_multimap& x);
    

    Requires: Hash and Pred shall satisfy the Swappable requirements ([swappable]).

    Effects: Exchanges the contents and hash policy and swaps the allocators of *this with that of x, followed by an unqualified swap of the Pred objects and an unqualified swap of the Hash objects of *this and x

    Complexity: Constant time

  11. After section [unord.set.cnstr] add a new section unordered_set modifiers [unord.set.modifiers] and add the following paragraphs:

    void swap(unordered_set& x);
    

    Requires: Hash and Pred shall satisfy the Swappable requirements ([swappable]).

    Effects: Exchanges the contents and hash policy and swaps the allocators of *this with that of x, followed by an unqualified swap of the Pred objects and an unqualified swap of the Hash objects of *this and x

    Complexity: Constant time

  12. After section [unord.multiset.cnstr] add a new section unordered_multiset modifiers [unord.multiset.modifiers] and add the following paragraphs:

    void swap(unordered_multiset& x);
    

    Requires: Hash and Pred shall satisfy the Swappable requirements ([swappable]).

    Effects: Exchanges the contents and hash policy and swaps the allocators of *this with that of x, followed by an unqualified swap of the Pred objects and an unqualified swap of the Hash objects of *this and x

    Complexity: Constant time

Date: 2010-10-21.18:28:33

[ 2009-10 Santa Cruz: ]

Leave as open. Pablo to provide wording.

Date: 2010-10-21.18:28:33

[ 2009-10 Santa Cruz: ]

Looked at, but took no action on as it overlaps too much with N2982. Waiting for a new draft WP.

Date: 2009-09-30.00:00:00

[ 2009-09-30 Daniel adds: ]

The outcome of this issue should be considered with the outcome of 1198 both in style and in content (e.g. bullet 9 suggests to define the semantic of void priority_queue::swap(priority_queue&) in terms of the member swap of the container).

Date: 2009-07-28.00:00:00

[ 2009-07-28 Daniel provided wording. ]

  1. It assumes that the proposed resolution for 883 is applied, which breaks the circularity of definition between member swap and free swap.
  2. It uses the notation of the pre-concept allocator trait allocator_propagation_map, which might be renamed after the next refactoring phase of generalized allocators.
  3. It requires that compare objects, key equal functions and hash functions in containers are swapped via unqualified free swap according to 594.
Date: 2010-10-21.18:28:33

[ 2009-07 Frankfurt: ]

Daniel to provide wording. N2590 is no longer applicable.

Date: 2010-10-21.18:28:33

[ Bellevue: ]

Move to Open and ask Alisdair to provide wording.

Date: 2008-01-14.00:00:00

It appears most containers declare but do not define a member-swap function.

This is unfortunate, as all overload the swap algorithm to call the member-swap function! (required for swappable guarantees [Table 37] and Container Requirements [Table 87])

Note in particular that Table 87 gives semantics of a.swap(b) as swap(a,b), yet for all containers we define swap(a,b) to call a.swap(b) - a circular definition.

A quick survey of clause 23 shows that the following containers provide a definition for member-swap:

array
queue
stack
vector

Whereas the following declare it, but do not define the semantics:

deque
list
map
multimap
multiset
priority_queue
set
unordered_map
unordered_multi_map
unordered_multi_set
unordered_set

Suggested resolution:

Provide a definition for each of the affected containers...

History
Date User Action Args
2011-08-23 20:07:26adminsetstatus: wp -> c++11
2010-10-21 18:28:33adminsetmessages: + msg3733
2010-10-21 18:28:33adminsetmessages: + msg3732
2010-10-21 18:28:33adminsetmessages: + msg3731
2010-10-21 18:28:33adminsetmessages: + msg3730
2010-10-21 18:28:33adminsetmessages: + msg3729
2010-10-21 18:28:33adminsetmessages: + msg3728
2010-10-21 18:28:33adminsetmessages: + msg3727
2010-10-21 18:28:33adminsetmessages: + msg3726
2010-10-21 18:28:33adminsetmessages: + msg3725
2010-10-21 18:28:33adminsetmessages: + msg3724
2010-10-21 18:28:33adminsetmessages: + msg3723
2008-01-14 00:00:00admincreate