C++
std::copy_n
Input iterator
STL
algorithms

Why does stdcopy_n not increment the Input iterator n times?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

std::copy_n can be surprising with input iterators because it does not need to advance the input iterator after copying the last element. The algorithm must copy n values, but because it returns the output iterator rather than the advanced input iterator, incrementing the input exactly n times is not part of its visible contract.

What std::copy_n Actually Guarantees

For a positive count, std::copy_n copies exactly n elements from the input range into the destination. That is the important post-condition.

cpp
1#include <algorithm>
2#include <iostream>
3#include <vector>
4
5int main() {
6    std::vector<int> src{1, 2, 3, 4, 5};
7    std::vector<int> dst(3);
8
9    std::copy_n(src.begin(), 3, dst.begin());
10
11    for (int value : dst) {
12        std::cout << value << ' ';
13    }
14}

The output is 1 2 3. The algorithm's job is to produce that result, not to expose an exact count of iterator increment operations.

Why the Input Iterator May Advance Only n - 1 Times

Think about the mechanics. The first element is already available at the initial iterator position. To copy n elements, the algorithm can:

  1. read the current element
  2. copy it to the destination
  3. advance to the next element only if another copy is still needed

So after copying the last requested element, there may be no reason to increment the input iterator one more time.

A conceptual implementation looks like this:

cpp
1template <class InputIt, class Size, class OutputIt>
2OutputIt my_copy_n(InputIt first, Size count, OutputIt result) {
3    if (count <= 0) {
4        return result;
5    }
6
7    *result = *first;
8    ++result;
9
10    for (Size i = 1; i < count; ++i) {
11        ++first;
12        *result = *first;
13        ++result;
14    }
15
16    return result;
17}

Notice that first is advanced before each additional element after the first one, so the loop performs only count - 1 increments.

Why This Matters More for Input Iterators

With random-access or forward iterators, developers rarely care about the precise number of increments. With input iterators, the behavior is more noticeable because they are single-pass and often tied to streams or proxy objects.

For example, with std::istream_iterator, incrementing consumes input from a stream:

cpp
1#include <algorithm>
2#include <iostream>
3#include <iterator>
4#include <sstream>
5#include <vector>
6
7int main() {
8    std::istringstream stream("10 20 30 40");
9    std::istream_iterator<int> first(stream), last;
10    std::vector<int> out;
11
12    std::copy_n(first, 3, std::back_inserter(out));
13
14    for (int value : out) {
15        std::cout << value << ' ';
16    }
17}

What you should rely on is that three values are copied. You should not rely on an extra increment after the third copied value unless the algorithm explicitly promises one, and std::copy_n does not.

The Return Type Explains the Design

std::copy_n returns the output iterator, not the advanced input iterator. That tells you a lot about the intended abstraction. The algorithm is designed around the destination position after copying, not around exposing where the input ended up.

If the standard had wanted to promise an advanced input iterator, it would have needed a different interface.

Compare With Other Algorithms Carefully

Some algorithms do return both iterators or otherwise expose the consumed range more explicitly. It is easy to import those expectations into copy_n, but they do not apply automatically.

The important lesson is to read the algorithm contract, not to infer behavior from what seems intuitively symmetrical.

Common Pitfalls

The biggest mistake is assuming that copying n elements must require n visible increments of the input iterator. The first element is already addressed by the initial iterator, so an extra post-copy advance is not necessary.

Another issue is expecting std::copy_n to return the advanced input iterator. It returns the output iterator, so that information is intentionally not part of the result.

Developers also overinterpret the behavior of input iterators such as stream iterators. Single-pass iterators often make internal stepping more noticeable, but the algorithm contract still centers on copied elements, not on externally observed increments.

Finally, when debugging algorithm behavior, verify post-conditions such as copied values and destination state rather than relying on assumptions about internal stepping.

Summary

  • 'std::copy_n guarantees that n elements are copied, not that the input iterator is incremented n times.'
  • The first element is already available at the initial iterator position, so only n - 1 further advances may be needed.
  • This is especially visible with single-pass input iterators such as std::istream_iterator.
  • The algorithm returns the output iterator, not the advanced input iterator.
  • Rely on the documented post-conditions, not on inferred internal iteration steps.

Course illustration
Course illustration

All Rights Reserved.