To Iterate Is Human, to Range Is Divine

To Iterate Is Human, to Range Is Divine

ost Standard Library algorithms operate on sequences whose boundaries are designated by a pair of iterators: one iterator marks the beginning of the sequence and another marks its end. Combining such a pair of iterators into a single object has several advantages in terms of code simplification, safety, and performance. The following sections will explain how to use the new C++09 range library and show some of its advantages.


The following Standard Library algorithms, which I have selected randomly from the header, exhibit a recurring pattern of verbosity and tedium:

template   void replace(ForwardIterator first,               ForwardIterator last,               const T& old_value,               const T& new_value);template   InputIterator find(InputIterator first,                      InputIterator last,                     const T& value);template  OutputIterator copy(InputIterator first,                       InputIterator last,			       OutputIterator result);

These algorithms, as well as std::sort, std::remove, and so forth, represent the beginning and the end of the sequence on which they operate by a pair of iterators.


Why not combine these two iterators into a single object? That’s exactly what a std::range does?it combines two iterators into a single compact and efficient object.

Instantiaton
You can construct a range from a pair of iterators, by copying an existing range object or by default constructing an empty range whose iterators are singular. A singular iterator is similar to a NULL pointer; the only safe operation that you can perform on a singular iterator is assigning a new value to it.

Author’s Note: There are currently two range libraries. The Boost range library is ready for immediate download and use with any existing C++ compiler. However, this 10 Minute Solution will exclusively use the range library that is currently being incorporated into the C++09 standard. The differences between these two libraries aren’t great anyway. I prefer the standard version because that’s what most C++ users will have at their disposal in the near future.

The range classes and functions are declared in the augmented standard header . All range functions are preceded by range_ to make them distinct from the traditional iterator-based functions. A complete list of the range library functions is available in the official C++09 proposal. For the sake of brevity, I will show only a few illustrative examples here.

The range_make() helper function creates a range from a pair of iterators:

std::vector  results;//...populate the vectorstd::range results_range=std::make_range(myvec.begin(), myvec.end());

To copy a range object you can use a copy constructor as usual, or the copy_range() helper function:

template       CopyableRange copy_range(const Range& r);std::range another_range=std::copy_range(results_range);//copy ctor version:std::range yet_another_range(another_range); 

Finally, creating an empty range is trivial:

std::range empty_range; //fill it later

Accessing a Range
The range library defines functions for accessing a range’s iterators and modifying them. In addition, it includes a set of overloaded operators such as ==, != for comparing ranges and sub-ranges.

The beginning of a range is equivalent to the first of the two iterators of a range. To extract that iterator, use range_begin(). Notice that this function assumes two other C++09 proposals, namely rvalue-references, and auto and decltype:.

template< class Range > auto range_begin( Range&& r ) -> decltype( r.begin() );

This C++09 syntax is a bit unfamiliar yet but the meaning is self-evident: range_begin() takes an rvalue reference to a range object r (recall that Range in this context is a template parameter). It returns an object whose type is that of the expression r.begin(). In simpler words, it returns an iterator that designates the beginning of the range.

In a similar vein, call range_end() to extract the end of the range:

template< class Range > auto range_end( Range&& r ) -> decltype( r.end());vector::iterator vbeg=range_begin(results_range),                  vend=range_end(results_range);

Ease, Safety…
Bounds checking is a major problem with built-in arrays. It’s also one of the biggest code safety threats. The main cause of array-related bugs is that an array’s name decays into a pointer. That pointer tells you only where the array begins, but not where it ends. It’s so easy to lose track of the array’s end and when that happens, all hell breaks loose. Ranges eliminate this potential bug as they combine the beginning and the end of the array into a single range object. Overloads of range_begin() and range_end() generate iterators from a built-in array automatically:

int arr[4]={1,2,999,5};std::range arr_range(range_begin(arr), range_end(arr));

How does it work? The arguments of range_begin() is “reference to an array of N elements of type T“:

template< class T, size_t N >T* range_begin( T(&arr)[N]);

This function returns arr, the address of the first element, which makes a perfect iterator (recall that built-in arrays are valid STL sequences). The end of this sequence is obtained by calling:

template< class T, size_t N > T* range_end( T(&arr)[N]);

which returns arr+N.

STL algorithms that take pairs of iterators will be augmented with corresponding overloads that take ranges instead. In the meantime, you can use ranges even with traditional C++03 algorithms. For example, the find() algorithm locates a certain value within an array of integers like this:

int* p=find(arr_range.begin(), arr_range.end(),999);	

Indeed, this version doesn’t look simpler than the traditional iterator-based version. However, it’s much safer since the use of ranges prevents the inadvertent creation of an invalid iterator.

When range-based versions of Standard Library algorithms become available, the previous find() call will change to:

int* p=find(arr_range, 999);

Which is both safer and syntactically simpler.

…And Efficiency
With respect to performance, the range library introduces a new class called std::sub_range which encapsulates the notion of a range within another range. sub_range is particularly useful in implementing efficient string manipulation algorithms. A string is represented as a range, and the substring being modified is represented as a sub_range thereof.

Share the Post:
XDR solutions

The Benefits of Using XDR Solutions

Cybercriminals constantly adapt their strategies, developing newer, more powerful, and intelligent ways to attack your network. Since security professionals must innovate as well, more conventional endpoint detection solutions have evolved

AI is revolutionizing fraud detection

How AI is Revolutionizing Fraud Detection

Artificial intelligence – commonly known as AI – means a form of technology with multiple uses. As a result, it has become extremely valuable to a number of businesses across

AI innovation

Companies Leading AI Innovation in 2023

Artificial intelligence (AI) has been transforming industries and revolutionizing business operations. AI’s potential to enhance efficiency and productivity has become crucial to many businesses. As we move into 2023, several

data fivetran pricing

Fivetran Pricing Explained

One of the biggest trends of the 21st century is the massive surge in analytics. Analytics is the process of utilizing data to drive future decision-making. With so much of

kubernetes logging

Kubernetes Logging: What You Need to Know

Kubernetes from Google is one of the most popular open-source and free container management solutions made to make managing and deploying applications easier. It has a solid architecture that makes

ransomware cyber attack

Why Is Ransomware Such a Major Threat?

One of the most significant cyber threats faced by modern organizations is a ransomware attack. Ransomware attacks have grown in both sophistication and frequency over the past few years, forcing

data dictionary

Tools You Need to Make a Data Dictionary

Data dictionaries are crucial for organizations of all sizes that deal with large amounts of data. they are centralized repositories of all the data in organizations, including metadata such as