C++ - Algorithms & Ranges Deep Dive

Overview

Estimated time: 70–90 minutes

Master the algorithms toolbox: transform, accumulate, partition/remove_if, sorting, and composing C++20 ranges pipelines. Learn when to copy vs view, projections, and performance tips.

Learning Objectives

  • Use key algorithms: transform, accumulate, copy_if/remove_if, partition, sort/stable_sort with comparators.
  • Build expressive ranges pipelines with views::filter, transform, take/drop; collect into containers safely.
  • Apply erase-remove and understand iterator invalidation and complexity.

Prerequisites

Transform and accumulate

#include <vector>
#include <numeric>
#include <algorithm>
#include <iostream>
int main(){
  std::vector v{1,2,3,4};
  std::vector sq(v.size());
  std::transform(v.begin(), v.end(), sq.begin(), [](int x){ return x*x; });
  int sum = std::accumulate(sq.begin(), sq.end(), 0);
  std::cout << sum << "\n"; // 30
}

Expected Output: 30

Filter with copy_if and erase-remove

#include <vector>
#include <algorithm>
#include <iostream>
int main(){
  std::vector xs{1,2,3,4,5,6};
  std::vector out;
  std::copy_if(xs.begin(), xs.end(), std::back_inserter(out), [](int x){return x%2==0;});
  xs.erase(std::remove_if(xs.begin(), xs.end(), [](int x){return x%2==0;}), xs.end());
  for (int x: out) std::cout << x << ' '; std::cout << "\n"; // 2 4 6
  for (int x: xs) std::cout << x << ' '; // 1 3 5
}

Partition and sort

#include <vector>
#include <algorithm>
#include <iostream>
int main(){
  std::vector v{5,1,4,2,3};
  std::partition(v.begin(), v.end(), [](int x){return x%2==0;}); // evens first
  std::sort(v.begin(), v.end());
  for (int x : v) std::cout << x << ' ';
}

Expected Output: 1 2 3 4 5

Ranges pipelines (C++20)

#include <vector>
#include <ranges>
#include <iostream>
int main(){
  std::vector v{1,2,3,4,5,6};
  auto pipe = v | std::views::filter([](int x){ return x%2==0; })
                 | std::views::transform([](int x){ return x*x; })
                 | std::views::take(2);
  std::vector out; for (int x : pipe) out.push_back(x);
  for (int x : out) std::cout << x << ' '; // 4 16
}

Beginner Boosters

#include 
#include 
#include 
int main(){
  std::vector v{1,2,3,4,5};
  std::cout << std::count_if(v.begin(), v.end(), [](int x){return x%2==0;}) << "\n"; // 2
  std::cout << (std::all_of(v.begin(), v.end(), [](int x){return x>0;})?"yes":"no") << "\n"; // yes
}
#include 
#include 
#include 
int main(){
  std::vector v{0,0,1,2,3,0};
  auto pipe = v | std::views::drop_while([](int x){return x==0;})
                 | std::views::take_while([](int x){return x>0;});
  for (int x : pipe) std::cout << x << ' '; // 1 2 3
}

Best practices

  • Prefer algorithms over manual loops for clarity and correctness.
  • Remember erase-remove to truly shrink containers.
  • With ranges views, be aware of dangling views; materialize into a container when needed.

Common Pitfalls

  • Iterators invalidated after erase/sort; don’t reuse stale iterators.
  • Capturing references to temporary ranges in long-lived views; copy when necessary.

Checks for Understanding

  1. What does remove_if return and why must you call erase?
  2. When should you materialize a view into a container?
Show answers
  1. It returns the new logical end after moving kept elements forward; erase to shrink the container.
  2. When you need ownership, random access, or long-lived data independent of the source.

Exercises

  1. Use ranges to produce the first three squares of even numbers from 1..20.
  2. Partition a vector by a predicate, then stable_sort each partition with a custom comparator.