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

### 774. Member `swap` undefined for most containers

Section: 22 [containers] Status: C++11 Submitter: Alisdair Meredith Opened: 2008-01-14 Last modified: 2016-01-28

Priority: Not Prioritized

View other active issues in [containers].

View all other issues in [containers].

View all issues with C++11 status.

Discussion:

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

[ Bellevue: ]

> Move to Open and ask Alisdair to provide wording.

[ 2009-07 Frankfurt: ]

> Daniel to provide wording. N2590 is no longer applicable.

[ 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.

[ 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).

[ 2009-10 Santa Cruz: ]

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

[ 2009-10 Santa Cruz: ]

> Leave as open. Pablo to provide wording.

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

> 1. Add a new Throws clause just after 99 [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 22.2.6.2 [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 22.2.7.2 [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 22.3 [sequences]/1:

>    > In addition to being available via inclusion of the `<algorithm>` header, the `swap` function templates in 25.7.3 [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 22.3.7.4 [array.special]:

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

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

> 6. 1. In 22.3.8 [deque], class template `deque` synopsis change as indicated:

>       >     void swap(deque<T,Alloc>&);

>    2. At the end of 22.3.8.4 [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.

> 7. 1. In 99 [forwardlist], class template `forward_list` synopsis change as indicated:

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

>    2. At the end of 99 [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.

> 8. 1. In 22.3.10 [list], class template `list` synopsis change as indicated:

>       >     void swap(list<T,Allocator>&);

>    2. At the end of 22.3.10.4 [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.

> 9. At the end of 22.6.5.4 [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 22.2.1 [container.requirements.general] p. 10 b. 5 ]

> 10. 1. In 22.3.11 [vector], class template `vector` synopsis change as indicated:

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

>     2. Change 22.3.11.3 [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`.

> 11. Insert a new paragraph just before 22.4 [associative]/1:

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

> 12. 1. In 22.4.4 [map], class template `map` synopsis change as indicated:

>        >     void swap(map<Key,T,Compare,Allocator>&);

>     2. At the end of 22.4.4.4 [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

> 13. 1. In 22.4.5 [multimap], class template `multimap` synopsis change as indicated:

>        >     void swap(multimap<Key,T,Compare,Allocator>&);

>     2. At the end of 22.4.5.3 [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

> 14. 1. In 22.4.6 [set], class template `set` synopsis change as indicated:

>        >     void swap(set<Key,Compare,Allocator>&);

>     2. After section 22.4.6.2 [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

> 15. 1. In 22.4.7 [multiset], class template `multiset` synosis, change as indicated:

>        >     void swap(multiset<Key,Compare,Allocator>&);

>     2. After section 22.4.7.2 [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

> 16. Insert a new paragraph just before 22.5 [unord] p. 1:

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

> 17. After section 22.5.4.3 [unord.map.elem] add a new section unordered_map modifiers 22.5.4.4 [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

> 18. After section 22.5.5.2 [unord.multimap.cnstr] add a new section unordered_multimap modifiers 22.5.5.3 [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

> 19. After section 22.5.6.2 [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

> 20. After section 22.5.7.2 [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

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

[ 2010 Pittsburgh: Ready for Pittsburgh. ]

Proposed resolution:

[ 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 22.2.1 [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 22.2.1 [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 22.2.1 [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 25.7.3 [alg.swap] is also available within the definition of every standard container's `swap` function.

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

Modify 22.2.6.2 [associative.reqmts.except] as follows:

> 23.2.4.1 Exception safety guarantees 22.2.6.2 [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 operator swap of the container's `PredCompare` object (if any).

Modify 22.2.7.2 [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 operator swap of the container's `Hash` or `Pred` object (if any).

Modify section 22.3.7.4 [array.special]:

> array specialized algorithms 22.3.7.4 [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 22.6 [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).