Why copy_n, fill_n and generate_n?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
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

