Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it defined to provide an inverted range to C++ standard algorithms?

Tags:

c++

std

c++11

Consider standard algorithms like, say, std::for_each.

template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f);

As far as I can tell, there is actually no requirement placed on the relative states of the two InputIterator arguments.

Does that mean that the following is technically valid? Or is it undefined? What can I realistically expect it to do?

std::vector<int> v{0,1,2,3,4};
std::for_each(
   v.begin()+3,  // range [3,0)
   v.begin(),
   [](int){}
);

geordi tells me:

error: function requires a valid iterator range [__first, __last). [+ 13 discarded lines]

but I can't tell how compliant this debug diagnostic is.


I came up with this question when trying to pedantically determine how explicit is defined the behaviour of the following:

std::vector<int> v; // <-- empty
std::for_each(      // <-- total no-op? stated or just left to implication?
   v.begin(),
   v.end(),
   [](int){}
);
like image 562
Lightness Races in Orbit Avatar asked Sep 21 '11 18:09

Lightness Races in Orbit


People also ask

What does include algorithm do in C++?

C++ Algorithm includes() C++ Algorithm includes() function returns true if every element from the sorted range [first2, last2) is found within the sorted range [first1, last1). It also returns true if [first2, last2) is empty.

How many algorithms in c++?

The 114 standard C++ algorithms.

Why do we use include algorithm?

The C++ function std::algorithm::includes() test whether first set is subset of another or not. This member function expects elements in sorted order. It use operator< for comparison.


2 Answers

The standard explicitly requires the last iterator to be reachable from the first iterator. That means that by incrementing first one should be able to eventually hit last.

24.1 Iterator requirements

...

6 An iterator j is called reachable from an iterator i if and only if there is a finite sequence of applications of the expression ++i that makes i == j. If j is reachable from i, they refer to the same container.

7 Most of the library’s algorithmic templates that operate on data structures have interfaces that use ranges. A range is a pair of iterators that designate the beginning and end of the computation. A range [i, i) is an empty range; in general, a range [i, j) refers to the elements in the data structure starting with the one pointed to by i and up to but not including the one pointed to by j. Range [i, j) is valid if and only if j is reachable from i. The result of the application of functions in the library to invalid ranges is undefined.

like image 100
AnT Avatar answered Sep 29 '22 01:09

AnT


The result is Undefined.


C++03 Standard: 25.1.1 For each and
C++11 Standard: 25.2.4 For each states:

template<class InputIterator, class Function>
Function for_each(InputIterator first, InputIterator last, Function f);

1 Effects: Applies f to the result of dereferencing every iterator in the range [first, last), starting from first and proceeding to last - 1

While another section defines the valid range [first,last) as:

C++03 Standard: 24.1 Iterator requirements and
C++11 Standard: 24.2.1 Iterator requirements

Para 7 for both:

Most of the library’s algorithmic templates that operate on data structures have interfaces that use ranges.A range is a pair of iterators that designate the beginning and end of the computation. A range [i, i) is an empty range; in general, a range [i, j) refers to the elements in the data structure starting with the one pointed to by i and up to but not including the one pointed to by j. Range [i, j) is valid if and only if j is reachable from i. The result of the application of functions in the library to invalid ranges is undefined.


Having remembered of reading this somewhere, just browsed through:

C++ Standard Library - A Tutorial and Reference - By Nicolai Josutils

This finds a mention in:

5.4.1 Ranges
The caller must ensure that the first and second arguments define a valid range. This is the case if the end of the range is reachable from the beginning by iterating through the elements. This means, it is up to the programmer to ensure that both iterators belong to the same container and that the beginning is not behind the end. If this is not the case, the behavior is undefined and endless loops or forbidden memory access may result.

like image 30
Alok Save Avatar answered Sep 29 '22 00:09

Alok Save