DEV Community

Sandor Dargo
Sandor Dargo

Posted on • Originally published at sandordargo.com

The big STL Algorithms tutorial: modifying sequence operations - turn things around

This article has been originally posted on my blog. If you would like to receive my latest articles, please sign up to my newsletter.

In this next part of the big STL algorithm tutorial, we will continue with two algorithms that help us to reverse the order of elements in a range:

  • reverse
  • reverse_copy

Let's get started!

reverse

It's as simple as you can imagine - by an STL algorithm. It takes a range defined by a pair of iterators and reverses the range, in place. It doesn't even have a return value. The only thing you have to pay attention to is to pass in the right iterators.

#include <iostream>
#include <algorithm>
#include <vector>

int main () {
  std::vector<int> numbers {1, 2, 3, 4, 5, 6, 7, 8, 9};

  std::reverse(numbers.begin(),numbers.end());

  std::cout << "numbers of original vector are reversed: ";
  for (auto number : numbers) {
    std::cout << ' ' << number;
  }
  std::cout << std::endl;

  return 0;
}
Enter fullscreen mode Exit fullscreen mode

reverse_copy

This algorithm is not much more complicated than reserve. The only difference is that, while reverse made in-place changes to a container, reverse_copy leaves the input intact and fills up an output container.

As you could have got used to it, the output is passed in by an iterator (here as a third parameter). You either make sure that the container under the iterator is big enough to accommodate all the elements that are going to be inserted or you pass in an iterator that can insert new elements, like in the below example.

#include <iostream>
#include <algorithm>
#include <vector>

int main () {
  std::vector<int> numbers {1, 2, 3, 4, 5, 6, 7, 8, 9};
  std::vector<int> reversedNumbers{};
  reversedNumbers.reserve(numbers.size());

  std::reverse_copy(numbers.begin(),numbers.end(),std::back_inserter(reversedNumbers));

  std::cout << "order of numbers in original vector hasn't changes: ";
  for (auto number : numbers) {
    std::cout << ' ' << number;
  }
  std::cout << std::endl;

  std::cout << "numbers in reversedNumbers are reversed: ";
  for (auto number : reversedNumbers) {
    std::cout << ' ' << number;
  }
  std::cout << std::endl;

  return 0;
}
Enter fullscreen mode Exit fullscreen mode

You can consider it as a certain part of our immutable programming toolbox, Why just a certain? As STL algorithms operate through iterators, not directly on containers, it cannot return you a new container, but it will modify the one that the passed in iterator points to.

Therefore it's not strongly part of an immutable toolbox, but one can make the point that it just takes a potentially empty container that was created on the line before, and then it should not be modified.

Sadly, your copy cannot be const given that reverse_copy already had to modify it. If you really what to show that it's a const vector, you have to wrap the transformation into its own function, somehow like this:

#include <iostream>
#include <algorithm>
#include <vector>

template<typename T>
const std::vector<T> reverse_const_copy(const std::vector<T>& input) {
    std::vector<T> reversedInput{};
    reversedInput.reserve(input.size());
    std::reverse_copy(input.begin(),input.end(),std::back_inserter(reversedInput));
    return reversedInput;
}

int main () {
  std::vector<int> numbers {1, 2, 3, 4, 5, 6, 7, 8, 9};
  const std::vector<int> reversedNumbers = reverse_const_copy(numbers);

  // reversedNumbers.push_back(0); // this does not compile as reversedNumbers is const

  std::cout << "order of numbers in original vector hasn't changes: ";
  for (auto number : numbers) {
    std::cout << ' ' << number;
  }
  std::cout << std::endl;

  std::cout << "numbers in reversedNumbers are reversed: ";
  for (auto number : reversedNumbers) {
    std::cout << ' ' << number;
  }
  std::cout << std::endl;

  return 0;
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

Today, we learned about 2 algorithms that help us to reverse the elements of a container, I think their usage didn't hide any big surprise. Besides we also saw how we can make const reversed copies, even if it needs some additional tinkering.

Next time we’ll learn about Sean Parent's favourite algorithms rotate and rotate_copy. Stay tuned!

Top comments (3)

Collapse
 
gapry profile image
Gapry

Hi, Sandor Dargo

I think the code snippets

std::vector<int> numbers {1, 2, 3, 4, 5, 6, 7, 8, 9};
const std::vector<int> reversedNumbers = reverse_const_copy(numbers);

is changed to as following by adopted keyword auto is better.

auto numbers         = std::vector<int>{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto reversedNumbers = reverse_const_copy(numbers); 

what do you think about this?

Best regards, Gapry.

Collapse
 
sandordargo profile image
Sandor Dargo

Thanks for your comment @gapry .

I think that in the second case, it's better and if you are looking for a direct replacement, I would go with const auto. If you'd change the return type of reverse_const_copy(), there would be nothing to do on the caller side.

In the first case, I don't think it's any better. If you want to change the type, you have to update it anyway and using auto in fact just makes the code more verbose without adding any benefits.

It's debatable that it would make the code more uniform, without any benefits and with a few extra chars, let's say it's a matter of personal preference/project guidelines.

Thanks for your ideas!

Collapse
 
gapry profile image
Gapry

Hi, @sandordargo

Thank you for your insights !

Best regards, Gapry.