Why copy_n, fill_n and generate_n?
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.
Introduction
The C++ Standard Library provides copy_n, fill_n, and generate_n alongside their range-based counterparts copy, fill, and generate. The _n variants take an explicit count instead of an end iterator, making them essential when the number of elements is known but the end iterator is not readily available — common with output iterators, stream iterators, and raw pointers. They also express intent more clearly when you want to operate on exactly N elements.
copy_n
Copies exactly n elements from a source to a destination:
Why Not Just copy?
copy requires both begin and end iterators for the source range. copy_n only needs the begin iterator and a count:
fill_n
Assigns a value to exactly n elements starting from an iterator:
fill vs fill_n
generate_n
Calls a generator function exactly n times, storing results starting from an iterator:
generate vs generate_n
When to Use _n Variants
| Scenario | Use _n variant | Why |
| Output iterators (ostream, back_inserter) | Yes | No end iterator available |
| Stream iterators (istream) | Yes | End = end of stream, but you want N items |
| Raw pointers without size | Yes | Count is known, end pointer requires arithmetic |
| Array with known length | Either | _n is slightly more readable |
| Container with begin/end | Prefer non-_n | Range-based is more idiomatic |
C++20 Ranges
C++20 provides ranges versions with additional safety:
Return Values
The _n variants return an iterator past the last element written:
Common Pitfalls
- Buffer overflow:
copy_n,fill_n, andgenerate_ndo not check that the destination has enough space. Writing past the end of a container is undefined behavior. Ensure the destination is large enough or useback_inserter. - Negative or zero count: Passing
n <= 0to_nfunctions is well-defined — they simply do nothing and return the input iterator. But accidentally passing a negative count (e.g., from signed integer arithmetic) is a logic bug. - Stateful generators and copies: If you pass a lambda by value to
generate_n, the lambda's state is copied. Use[&]capture orstd::refto ensure state is shared if needed. - Performance: The
_nvariants have identical performance to their range-based counterparts. The choice is about API ergonomics, not speed. - Prefer ranges in C++20: If targeting C++20,
std::views::take(n)combined withstd::ranges::copyis often more readable thancopy_n.
Summary
- Use
copy_n,fill_n,generate_nwhen you have a count but no end iterator (output iterators, streams, raw pointers) - Use the range-based
copy,fill,generatewhen you have both begin and end iterators _nvariants return an iterator past the last written element — useful for chaining operations- Always ensure the destination has enough capacity —
_nfunctions do not bounds-check - In C++20, prefer
std::rangesandstd::views::take(n)for a safer, more expressive alternative
Related reading
- Why current term in raft consensus algorithm must be monotonic
- Why deletion of elements of hash table using doubly-linked list is O1?
- Why DFS and not BFS for finding cycle in graphs
- Why do all-pair shortest path algorithms work with negative weights?
- Why do I have to always specify the range in STL''s algorithm functions explicitly, even if I want to work on the whole container?
- Why do we need to add a '0' null at the end of a character array in C?
- Why do divide and conquer algorithms often run faster than brute force?
- Why do we ignore co-efficients in Big O notation?

DSA Fundamentals
Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Data Structures & Algorithms practice on Codemia
Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.