Range Based For loop

Range-based for loops, introduced in C++11, provide a convenient syntax for iterating over elements of a range, such as arrays, containers, or other sequences. They offer a more concise and readable alternative to traditional for loops, especially when working with containers that support iterators.

Benefits of Range-Based for Loops

  • Readability: They focus on the element itself, improving code clarity.
  • Conciseness: They require less code compared to traditional for loops.
  • Maintainability: Changes to container size don’t affect loop logic.
  • Type Safety: The compiler infers element types, reducing errors.

Basic Syntax

				
					for (range_declaration : range_expression) {
  // Code to be executed for each element in the range
}

				
			
  • range_declaration: Declares a variable to hold the current element during each iteration. Its type is usually inferred by the compiler based on the container’s element type (e.g., int for an integer array).
  • range_expression: An expression that evaluates to a container or range of elements you want to iterate over.

Example: Iterating over an Array

				
					#include <iostream>

int main() {
  int numbers[] = {1, 2, 3, 4, 5};

  // Range-based for loop
  for (int num : numbers) {
    std::cout << num << " ";
  }
  std::cout << std::endl;

  return 0;
}

				
			
				
					// output //
1 2 3 4 5

				
			

Explanation:

  • The loop iterates over the numbers array.
  • In each iteration, the current element (num) is assigned the value of the corresponding array element.
  • The loop body simply prints each element.

Iterating over a Vector

				
					#include <iostream>
#include <vector>

int main() {
  std::vector<std::string> names = {"Alice", "Bob", "Charlie"};

  // Range-based for loop
  for (const std::string& name : names) {
    std::cout << name << " ";
  }
  std::cout << std::endl;

  return 0;
}

				
			
				
					// output //
Alice Bob Charlie

				
			

Explanation:

  • The loop iterates over the names vector of strings.
  • The const std::string& part in range_declaration ensures we get a read-only reference to each element, preventing accidental modification within the loop.

Advanced Topics

Iterating over a Container with Modifications

If you need to modify elements within the loop, you can either:

  • Non-const Reference: Use a non-const reference in range_declaration (e.g., int& num). This allows modification, but be cautious to avoid unintended side effects.
				
					#include <iostream>
#include <vector>

int main() {
  std::vector<int> numbers = {1, 2, 3, 4, 5};

  // Loop with modification
  for (int& num : numbers) {
    num *= 2; // Double each element
  }

  for (int num : numbers) {
    std::cout << num << " ";
  }
  std::cout << std::endl;

  return 0;
}

				
			
				
					// output //
2 4 6 8 10

				
			
  • std::copy Function: Use std::copy to create a modified copy of the container within the loop, avoiding potential issues with modifying the original during iteration.

Iterating over Specific Ranges

Example 1: Iterating over a Subrange of a Container

				
					#include <iostream>
#include <vector>

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

    // Iterating over a subrange of the vector (from index 2 to 5)
    for (auto it = numbers.begin() + 2; it != numbers.begin() + 6; ++it) {
        std::cout << *it << " ";
    }
    std::cout << std::endl;

    return 0;
}

				
			
				
					// Output //
3 4 5 6
				
			

Explanation: In this example, we use iterators to specify the range we want to iterate over. By using numbers.begin() + 2 and numbers.begin() + 6, we define a subrange starting from the third element (index 2) up to the seventh element (index 5) of the vector numbers.

Iterating over a Subset of an Array

				
					#include <iostream>

int main() {
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // Iterating over a subset of the array (from index 3 to 7)
    for (int i = 3; i <= 7; ++i) {
        std::cout << arr[i] << " ";
    }
    std::cout << std::endl;

    return 0;
}

				
			
				
					// Output //
4 5 6 7 8
				
			

Explanation: In this example, we use a traditional for loop with indices to specify the range we want to iterate over. By starting from index 3 and ending at index 7 (inclusive), we define a subset of elements within the array arr to iterate over.

Nested Range-Based for Loops

You can nest range-based for loops to iterate over elements in multi-dimensional containers like 2D arrays or nested containers:

				
					#include <iostream>
#include <vector>

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

    // Nested range-based for loops to iterate over each element in the matrix
    for (auto& row : matrix) {
        for (auto& element : row) {
            std::cout << element << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

				
			
				
					// Output //
1 2 3 
4 5 6 
7 8 9 

				
			

Explanation:

  • In the example, we have a 2D vector matrix representing a 3×3 matrix.
  • The outer range-based for loop iterates over each row of the matrix. For each row, row represents a reference to the current row.
  • Inside the outer loop, the inner range-based for loop iterates over each element in the current row. For each element, element represents a reference to the current element.
  • The inner loop prints each element separated by a space.
  • After printing all elements in a row, a newline is printed to move to the next row.
  • Thus, the output displays each element of the matrix, with each row printed on a separate line.

Iterating Over Key-Value Pairs

The basic syntax for iterating over key-value pairs in maps using a range-based for loop is:

				
					for (const auto& pair : map) {
    // Access pair.first for the key and pair.second for the value
}

				
			

Where:

  • map is the map container.
  • pair is a reference to each key-value pair in the map.
  • pair.first accesses the key, and pair.second accesses the corresponding value.

Let’s consider an example where we have a std::map storing the ages of individuals, where the name of the individual serves as the key and their age serves as the value. We’ll iterate over the key-value pairs to print each name and age.

				
					#include <iostream>
#include <map>
#include <string>

int main() {
    std::map<std::string, int> ages = {
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35}
    };

    // Iterate over key-value pairs in the map
    for (const auto& pair : ages) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

				
			
				
					// output //
Alice: 30
Bob: 25
Charlie: 35

				
			

Explanation:

  • We define a std::map named ages that stores the ages of individuals as key-value pairs, where the name is the key and the age is the value.
  • We use a range-based for loop to iterate over each key-value pair in the map.
  • Inside the loop, we access pair.first to retrieve the name (key) and pair.second to retrieve the age (value) of each individual.
  • We print each name and age pair to the console.

Modifying Values While Iterating

It’s possible to modify the values stored in the map while iterating over key-value pairs. However, care must be taken to avoid invalidating iterators, especially when modifying the keys.

Let’s consider an example where we increment the age of each individual by 1 while iterating over the map.

				
					#include <iostream>
#include <map>
#include <string>

int main() {
    std::map<std::string, int> ages = {
        {"Alice", 30},
        {"Bob", 25},
        {"Charlie", 35}
    };

    // Iterate over key-value pairs in the map
    for (auto& pair : ages) {
        pair.second++; // Increment each age by 1
    }

    // Print the modified ages
    for (const auto& pair : ages) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }

    return 0;
}

				
			
				
					// output //
Alice: 31
Bob: 26
Charlie: 36

				
			

Explanation:

  • We iterate over each key-value pair in the ages map using a range-based for loop.
  • Inside the loop, we use pair.second++ to increment each age by 1.
  • After modification, we iterate over the map again to print the updated ages to the console.

Const Correctness

By default, range-based for loops provide a const reference to the element, preventing accidental modifications. If you need to modify elements, use a non-const reference as mentioned earlier.

Limitations

  • Range-based for loops typically cannot iterate in reverse order or access element indices directly. Use traditional for loops if these functionalities are required.
  • They might be slightly less efficient than traditional for loops in some scenarios, but the readability benefits often outweigh this.

Range-based for loops are a valuable addition to the C++ programmer's toolkit. They enhance code readability, maintainability, and type safety by providing a concise way to iterate over containers. Understanding their syntax, advanced features, and limitations will help you leverage them effectively in your C++ programs. Happy coding !❤️

Table of Contents

Contact here

Copyright © 2025 Diginode

Made with ❤️ in India