isocpp / isocpp/CppCoreGuidelines

Guideline for how to declare variables in a range-based for loop

Open
#2,115 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
CSS
Stars
45.3k
Forks
5.6k
PR merge metrics
No merged PRs in 30d

Description

A question which comes up every now and then is what type of loop variable you should use for range-based for, particularly when no mutation takes place.

// case (1) - cheap to copy
for (int x : container) // disallowed in this form by Con.1, should be 'const int'
// vs
for (const int &x : container)
// case (2) - expensive to copy
for (string x : container) // disallowed in this form by ES.71, should be 'const string &x'
// vs
for (const string &x : container)

I think we should recommend to always declare the loop variable as a reference, never as a value, and here's why:

  1. The rule is simple and consistent.
  2. When mutating a T& variable in the loop, you are already forced to follow it by the language.
  3. If you aren't, and you have case (2), then ES.71 already tells you to.
  4. Otherwise, if you are following Con.1, then const T x is only one character away from const T &x, so it costs very little effort to follow this rule.
  5. It is possible and relatively easy to enforce with automatic tooling.
  6. It prevents bugs related to taking the address of the local variable, instead of taking the address of the object within the container.
  7. Even for weird iterators like std::ranges::iota_view::iterator, where their reference is actually a value, this method is robust because const& allows for temporary materialization.

In essence, I don't see any benefit to non-reference loop variables, and the alternative is consistent, easy, correct by default, and already recommended in part.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing the existing Con.1 and ES.71 guidance and the five comments on this issue. Determine whether the proposed rule should replace or clarify those recommendations, including the cited range-based-for cases. Done means reaching a decision and documenting the agreed guidance in the relevant C++ Core Guidelines section.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
documentation
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.