Document number: N1860=05-0120

Howard E. Hinnant
2005-08-26

Rvalue Reference Recommendations for Chapter 25

Contents

Related papers

Rvalue Reference Recommendations for Chapter 20
Rvalue Reference Recommendations for Chapter 21
Rvalue Reference Recommendations for Chapter 23
Rvalue Reference Recommendations for Chapter 24
Rvalue Reference Recommendations for Chapter 26
Rvalue Reference Recommendations for Chapter 27

Introduction

This paper recommends proposed wording with respect to the rvalue reference for the C++0X working draft. This paper restricts its scope to Chapter 25 "Algorithms library" for the purpose of breaking the library work associated with the rvalue reference up into manageable chunks. This paper largely follows the lead of N1771: Impact of the rvalue reference on the Standard Library, but adds more detail as appropriate. Refer to N1771 for detailed motivation for these changes.

With the exception of this introduction, all non-proposed wording will have a background color and formatting that

looks like this, so that motivation and description is more easily distinguished from proposed wording.

In the proposed wording below, text to be inserted is formatted like this, while wording to be deleted is formatted like this.

The proposed wording in this paper accomplishes three tasks:

  1. New algorithms move and move_backward are introduced.
  2. The random_shuffle signature is altered to accept rvalue generators.
  3. The requirements on the value_type of several algorithms are reduced from CopyConstructible and CopyAssignable to MoveConstructible and MoveAssignable.

This third action is the most important as it allows clients to use these algorithms with sequences of movable but non-copyable types. For example:

vector<unique_ptr<T> > v;
...
sort(v.begin(), v.end(), indirect_less());  // ok to sort unique_ptr's

25 - Algorithms library

Header <algorithm> synopsis

The synopsis is updated with two new functions: move and move_backward. These two functions are merely convenience functions as any copying style algorithm can be turned into a moving style algorithm with the use of move_iterator. For example:

copy(make_move_iterator(first), make_move_iterator(last), result);

is equivalent to:

move(first, last, result);

However the anticipated frequency of use of move and move_backward warrant the special treatment.

Additionally the signature (though not the description) of random_shuffle is modified so as to accept lvalue and rvalue random number generators.

namespace std {

  ...

  //  lib.alg.modifying.operations, modifying sequence operations:
  //  lib.alg.copy, copy:
  template<class InputIterator, class OutputIterator>
    OutputIterator copy(InputIterator first, InputIterator last,
			OutputIterator result);
  template<class BidirectionalIterator1, class BidirectionalIterator2>
    BidirectionalIterator2
      copy_backward
	(BidirectionalIterator1 first, BidirectionalIterator1 last,
	 BidirectionalIterator2 result);

  template<class InputIterator, class OutputIterator>
    OutputIterator move(InputIterator first, InputIterator last,
			OutputIterator result);
  template<class BidirectionalIterator1, class BidirectionalIterator2>
    BidirectionalIterator2
      move_backward
	(BidirectionalIterator1 first, BidirectionalIterator1 last,
	 BidirectionalIterator2 result);

  ...

  template<class RandomAccessIterator>
    void random_shuffle(RandomAccessIterator first,
			RandomAccessIterator last);
  template<class RandomAccessIterator, class RandomNumberGenerator>
    void random_shuffle(RandomAccessIterator first,
			RandomAccessIterator last,
			RandomNumberGenerator&& rand);

  ...

}

25.2 - Mutating sequence operations

Insert new section for move and move_backward.

25.2.2 - Move


template<class InputIterator, class OutputIterator>
  OutputIterator move(InputIterator first, InputIterator last,
                      OutputIterator result);

-1- Effects: Moves elements in the range [first, last) to the range [result, result + (last - first)) starting from first and proceeding to last. For each non-negative integer n < (last-first), performs *(result + n) = std::move(*(first + n)).

-2- Returns: result + (last - first).

-3- Requires: result shall not be in the range [first, last).

-4- Complexity: Exactly last - first move assignments.


template<class BidirectionalIterator1, class BidirectionalIterator2>
  BidirectionalIterator2
    move_backward(BidirectionalIterator1 first,
                  BidirectionalIterator1 last,
                  BidirectionalIterator2 result);

-5- Effects: Moves elements in the range [first, last) to the range [result - (last - first), result) starting from last - 1 and proceeding to first . *

[Footnote: move_backward should be used instead of move when last is in the range [result - (last - first), result). -- end footnote]

For each positive integer n <= (last - first), performs *(result - n) = std::move(*(last - n)).

-6- Requires: result shall not be in the range [first, last).

-7- Returns: result - (last - first).

-8- Complexity: Exactly last - first move assignments.

25.2.23 - Swap

Reduce requirements for swap to MoveConstructible and MoveAssignable.

template<class T> void swap(T& a, T& b);

-1- Requires: Type T is CopyConstructible (lib.copyconstructible) MoveConstructible and Assignable (lib.container.requirements) MoveAssignable.

25.2.78 - Remove

Reduce requirements for remove and remove_if to MoveConstructible and MoveAssignable.

template<class ForwardIterator, class T>
  ForwardIterator remove(ForwardIterator first, ForwardIterator last,
                         const T& value);

template<class ForwardIterator, class Predicate>
  ForwardIterator remove_if(ForwardIterator first, ForwardIterator last,
                            Predicate pred);

-1- Requires: The type of *first shall satisfy the Assignable MoveAssignable requirements.

-2- Effects: Eliminates all the elements referred to by iterator i in the range [first, last) for which the following corresponding conditions hold: *i == value, pred(*i) != false.

-3- Returns: The end of the resulting range.

-4- Remarks: Stable.

-5- Complexity: Exactly last - first applications of the corresponding predicate.

25.2.89 - Unique

Reduce requirements for unique to MoveConstructible and MoveAssignable.

template<class ForwardIterator>
  ForwardIterator unique(ForwardIterator first, ForwardIterator last);

template<class ForwardIterator, class BinaryPredicate>
  ForwardIterator unique(ForwardIterator first, ForwardIterator last,
                         BinaryPredicate pred);

-1- Effects: Eliminates all but the first element from every consecutive group of equal elements referred to by the iterator i in the range [first, last) for which the following corresponding conditions hold: *i == *(i - 1) or pred(*i, *(i - 1)) != false

-2- Requires: The comparison function shall be an equivalence relation. The type of *first shall satisfy the MoveAssignable requirements.

-3- Returns: The end of the resulting range.

-4- Complexity: If the range (last - first) is not empty, exactly (last - first) - 1 applications of the corresponding predicate, otherwise no applications of the predicate.

25.2.910 - Rotate

Reduce requirements for rotate to MoveConstructible and MoveAssignable. Note that we already have Swappable as well.

template<class ForwardIterator>
  void rotate(ForwardIterator first, ForwardIterator middle,
              ForwardIterator last);

-1- Effects: For each non-negative integer i < (last - first), places the element from the position first + i into position first + (i + (last - middle)) % (last - first).

-2- Remarks: This is a left rotate.

-3- Requires: [first, middle) and [middle, last) are valid ranges. The type of *first shall satisfy the Swappable requirements (20.1.4), the MoveConstructible requirements, and the MoveAssignable requirements.

-4- Complexity: At most last - first swaps.

25.2.1112 - Random shuffle

Change the signature of random_shuffle. No other change is needed for the specification of random_shuffle.

template<class RandomAccessIterator>
  void random_shuffle(RandomAccessIterator first,
                      RandomAccessIterator last);

template<class RandomAccessIterator, class RandomNumberGenerator>
  void random_shuffle(RandomAccessIterator first,
                      RandomAccessIterator last,
                      RandomNumberGenerator&& rand);

25.2.1213 - Partitions

Reduce requirements for stable_partition to MoveConstructible and MoveAssignable. Note that we already have Swappable as well.

template<class BidirectionalIterator, class Predicate>
  BidirectionalIterator
    stable_partition(BidirectionalIterator first,
                     BidirectionalIterator last, Predicate pred);

-5- Effects: Places all the elements in the range [first, last) that satisfy pred before all the elements that do not satisfy it.

-6- Returns: An iterator i such that for any iterator j in the range [first, i), pred(*j) != false, and for any iterator k in the range [i, last), pred(*j) == false. The relative order of the elements in both groups is preserved.

-7- Requires: The type of *first shall satisfy the Swappable requirements (20.1.4), the MoveConstructible requirements, and the MoveAssignable requirements.

-8- Complexity: At most (last - first) * log(last - first) swaps, but only linear number of swaps if there is enough extra memory. Exactly last - first applications of the predicate.

25.3 - Sorting and related operations

25.3.1 - Sorting

25.3.1.1 - sort

Reduce requirements for sort to MoveConstructible and MoveAssignable. Note that we already have Swappable as well.

template<class RandomAccessIterator>
  void sort(RandomAccessIterator first, RandomAccessIterator last);

template<class RandomAccessIterator, class Compare>
  void sort(RandomAccessIterator first, RandomAccessIterator last,
            Compare comp);

-1- Effects: Sorts the elements in the range [first, last).

-2- Requires: The type of *first shall satisfy the Swappable requirements (20.1.4), the MoveConstructible requirements, and the MoveAssignable requirements.

-3- Complexity: Approximately N log N (where N == last - first) comparisons on the average.*

25.3.1.2 - stable_sort

Reduce requirements for stable_sort to MoveConstructible and MoveAssignable. Note that we already have Swappable as well.

template<class RandomAccessIterator>
  void stable_sort(RandomAccessIterator first, RandomAccessIterator last);

template<class RandomAccessIterator, class Compare>
  void stable_sort(RandomAccessIterator first, RandomAccessIterator last,
                   Compare comp);

-1- Effects: Sorts the elements in the range [first, last).

-2- Requires: The type of *first shall satisfy the Swappable requirements (20.1.4), the MoveConstructible requirements, and the MoveAssignable requirements.

-3- Complexity: It does at most N(log N)2 (where N == last - first) comparisons; if enough extra memory is available, it is N log N.

-4- Remarks: Stable.

25.3.1.3 - partial_sort

Reduce requirements for partial_sort to MoveConstructible and MoveAssignable. Note that we already have Swappable as well.

template<class RandomAccessIterator>
  void partial_sort(RandomAccessIterator first,
                    RandomAccessIterator middle,
                    RandomAccessIterator last);

template<class RandomAccessIterator, class Compare>
  void partial_sort(RandomAccessIterator first,
                    RandomAccessIterator middle,
                    RandomAccessIterator last,
                    Compare comp);

-1- Effects: Places the first middle - first sorted elements from the range [first, last) into the range [first, middle). The rest of the elements in the range [middle, last) are placed in an unspecified order.

-2- Requires: The type of *first shall satisfy the Swappable requirements (20.1.4), the MoveConstructible requirements, and the MoveAssignable requirements.

-3- Complexity: It takes approximately (last - first) * log(middle - first) comparisons.

25.3.1.4 - partial_sort_copy

Reduce requirements for partial_sort to MoveConstructible and CopyAssignable. Note that we already have Swappable as well. Also note that while CopyAssignable is required, CopyConstructible is not.

template<class InputIterator, class RandomAccessIterator>
  RandomAccessIterator
    partial_sort_copy(InputIterator first, InputIterator last,
                      RandomAccessIterator result_first,
                      RandomAccessIterator result_last);

template<class InputIterator, class RandomAccessIterator,
         class Compare>
  RandomAccessIterator
    partial_sort_copy(InputIterator first, InputIterator last,
                      RandomAccessIterator result_first,
                      RandomAccessIterator result_last,
                      Compare comp);

-1- Effects: Places the first min(last - first, result_last - result_first) sorted elements into the range [result_first, result_first + min(last - first, result_last - result_first)).

-2- Returns: The smaller of: result_last or result_first + (last - first)

-3- Requires: The type of *result_first shall satisfy the Swappable requirements (20.1.4), the MoveConstructible requirements, and the CopyAssignable requirements.

-4- Complexity: Approximately (last - first) * log(min(last - first, result_last - result_first)) comparisons.

25.3.2 - Nth element

Reduce requirements for nth_element to MoveConstructible and MoveAssignable. Note that we already have Swappable as well.

template<class RandomAccessIterator>
  void nth_element(RandomAccessIterator first, RandomAccessIterator nth,
                   RandomAccessIterator last);

template<class RandomAccessIterator, class Compare>
  void nth_element(RandomAccessIterator first, RandomAccessIterator nth,
                   RandomAccessIterator last,  Compare comp);

-1- After nth_element the element in the position pointed to by nth is the element that would be in that position if the whole range were sorted. Also for any iterator i in the range [first, nth) and any iterator j in the range [nth, last) it holds that: !(*i > *j) or comp(*j, *i) == false.

-2- Requires: The type of *first shall satisfy the Swappable requirements (20.1.4), the MoveConstructible requirements, and the MoveAssignable requirements.

-3- Complexity: Linear on average.

25.3.4 - Merge

Reduce requirements for inplace_merge to MoveConstructible and MoveAssignable. Note that we already have Swappable as well.

template<class BidirectionalIterator>
  void inplace_merge(BidirectionalIterator first,
                     BidirectionalIterator middle,
                     BidirectionalIterator last);

template<class BidirectionalIterator, class Compare>
  void inplace_merge(BidirectionalIterator first,
                     BidirectionalIterator middle,
                     BidirectionalIterator last, Compare comp);

-6- Effects: Merges two sorted consecutive ranges [first, middle) and [middle, last), putting the result of the merge into the range [first, last). The resulting range will be in non-decreasing order; that is, for every iterator i in [first, last) other than first, the condition *i < *(i - 1) or, respectively, comp(*i, *(i - 1)) will be false.

-7- Requires: The type of *first shall satisfy the Swappable requirements (20.1.4), the MoveConstructible requirements, and the MoveAssignable requirements.

-8- Complexity: When enough additional memory is available, (last - first) - 1 comparisons. If no additional memory is available, an algorithm with complexity N log N (where N is equal to last - first) may be used.

-9- Remarks: Stable.

25.3.6 - Heap operations

Reduce requirements for the heap operations to MoveConstructible and MoveAssignable (no longer requiring CopyConstructible and CopyAssignable). Note that we already have Swappable as well for pop_heap and sort_heap.

25.3.6.1 - push_heap
template<class RandomAccessIterator>
  void push_heap(RandomAccessIterator first, RandomAccessIterator last);

template<class RandomAccessIterator, class Compare>
  void push_heap(RandomAccessIterator first, RandomAccessIterator last,
                 Compare comp);

-1- Effects: Places the value in the location last - 1 into the resulting heap [first, last).

-2- Requires: The range [first, last - 1) shall be a valid heap. The type of *first shall satisfy the MoveConstructible requirements, and the MoveAssignable requirements.

-3- Complexity: At most log(last - first) comparisons.

25.3.6.2 - pop_heap
template<class RandomAccessIterator>
  void pop_heap(RandomAccessIterator first, RandomAccessIterator last);

template<class RandomAccessIterator, class Compare>
  void pop_heap(RandomAccessIterator first, RandomAccessIterator last,
                Compare comp);

-1- Effects: Swaps the value in the location first with the value in the location last - 1 and makes [first, last - 1) into a heap.

-2- Requires: The range [first, last) shall be a valid heap. The type of *first shall satisfy the Swappable requirements (20.1.4), the MoveConstructible requirements, and the MoveAssignable requirements.

-3- Complexity: At most 2 * log(last - first) comparisons.

25.3.6.3 - make_heap
template<class RandomAccessIterator>
  void make_heap(RandomAccessIterator first, RandomAccessIterator last);

template<class RandomAccessIterator, class Compare>
  void make_heap(RandomAccessIterator first, RandomAccessIterator last,
                 Compare comp);

-1- Effects: Constructs a heap out of the range [first, last).

-2- Requires: The type of *first shall satisfy the MoveConstructible requirements, and the MoveAssignable requirements.

-3- Complexity: At most 3 * (last - first) comparisons.

25.3.6.4 - sort_heap
template<class RandomAccessIterator>
  void sort_heap(RandomAccessIterator first, RandomAccessIterator last);

template<class RandomAccessIterator, class Compare>
  void sort_heap(RandomAccessIterator first, RandomAccessIterator last,
                 Compare comp);

-1- Effects: Sorts elements in the heap [first, last).

-2- Requires: The range [first, last) shall be a valid heap. The type of *first shall satisfy the Swappable requirements (20.1.4), the MoveConstructible requirements, and the MoveAssignable requirements.

-3- Complexity: At most N log N comparisons (where N == last - first).