C++ Generate Algorithms: std::fill, std::generate,
이 글의 핵심
std::fill writes a single value, std::generate calls a function for each element, and std::iota writes a sequential series. This guide covers all three with working examples including proper C++11 random number generation.
Overview
The C++ standard library has three algorithms for filling ranges with values:
| Algorithm | Header | Writes | Use when |
|---|---|---|---|
std::fill | <algorithm> | Same value to all | Resetting to zero, marking flags |
std::fill_n | <algorithm> | Same value to first N | Partial initialization |
std::generate | <algorithm> | Callable result per element | Computed or random values |
std::generate_n | <algorithm> | Callable for N elements | Appending generated data |
std::iota | <numeric> | Sequential increments | Index sequences, ranges |
std::fill
Writes the same value to every element in a range:
#include <algorithm>
#include <vector>
#include <array>
#include <iostream>
int main() {
// Fill entire vector
std::vector<int> v(8);
std::fill(v.begin(), v.end(), 42);
// v: {42, 42, 42, 42, 42, 42, 42, 42}
// Fill part of a vector
std::fill(v.begin() + 2, v.begin() + 5, 99);
// v: {42, 42, 99, 99, 99, 42, 42, 42}
// Works on any container
std::array<bool, 10> flags;
std::fill(flags.begin(), flags.end(), false);
// Works on C arrays too
int arr[5];
std::fill(arr, arr + 5, -1);
// arr: {-1, -1, -1, -1, -1}
}
std::fill_n
Fill exactly N elements starting at a position:
std::vector<int> v(10, 0);
// Set first 5 elements to 1
std::fill_n(v.begin(), 5, 1);
// v: {1, 1, 1, 1, 1, 0, 0, 0, 0, 0}
// Append N elements to a vector (with back_inserter)
std::vector<int> result;
std::fill_n(std::back_inserter(result), 4, 7);
// result: {7, 7, 7, 7}
std::generate
Calls a callable for each element and writes the result. The callable takes no arguments and returns a value:
#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v(5);
// Incrementing counter via stateful lambda
int counter = 0;
std::generate(v.begin(), v.end(), [&counter] {
return counter++;
});
// v: {0, 1, 2, 3, 4}
// Alternating values
bool toggle = false;
std::generate(v.begin(), v.end(), [&toggle] {
toggle = !toggle;
return toggle ? 1 : 0;
});
// v: {1, 0, 1, 0, 1}
// Fibonacci sequence
int a = 0, b = 1;
std::generate(v.begin(), v.end(), [&a, &b] {
int current = a;
int next = a + b;
a = b;
b = next;
return current;
});
// v: {0, 1, 1, 2, 3}
}
std::generate_n
Generate N elements and append to a container:
#include <algorithm>
#include <vector>
#include <iterator>
int main() {
std::vector<int> v;
// Append 5 squares
int n = 0;
std::generate_n(std::back_inserter(v), 5, [&n] {
return n * n++; // 0, 1, 4, 9, 16
});
// v: {0, 1, 4, 9, 16}
}
std::iota
Fills a range with consecutively incremented values. Defined in <numeric>:
#include <numeric>
#include <vector>
#include <list>
#include <iostream>
int main() {
// Fill with 0, 1, 2, 3, 4
std::vector<int> v(5);
std::iota(v.begin(), v.end(), 0);
// v: {0, 1, 2, 3, 4}
// Start from a different value
std::vector<int> w(5);
std::iota(w.begin(), w.end(), 10);
// w: {10, 11, 12, 13, 14}
// Works with any incrementable type — including chars
std::vector<char> letters(5);
std::iota(letters.begin(), letters.end(), 'a');
// letters: {'a', 'b', 'c', 'd', 'e'}
// Build an index array for indirect sorting
std::vector<int> indices(10);
std::iota(indices.begin(), indices.end(), 0);
// indices: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
// then sort indices by comparing data[i]
}
Indirect Sorting with iota
A common pattern: sort an index array instead of the data, to get sorted order without moving elements:
#include <numeric>
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>
int main() {
std::vector<std::string> names = {"Charlie", "Alice", "Bob", "Dave"};
// Build indices 0..n-1
std::vector<int> indices(names.size());
std::iota(indices.begin(), indices.end(), 0);
// Sort indices by name value
std::sort(indices.begin(), indices.end(),
[&names](int a, int b) { return names[a] < names[b]; });
// Print in sorted order without moving the original vector
for (int i : indices) {
std::cout << names[i] << '\n'; // Alice, Bob, Charlie, Dave
}
}
Random Number Generation with generate
Use C++11 <random> instead of rand():
#include <algorithm>
#include <random>
#include <vector>
#include <iostream>
int main() {
// Set up random engine and distribution
std::mt19937 engine(std::random_device{}()); // Mersenne Twister, seeded
std::uniform_int_distribution<int> dist(1, 100); // integers in [1, 100]
// Fill vector with random values
std::vector<int> v(10);
std::generate(v.begin(), v.end(), [&engine, &dist] {
return dist(engine);
});
for (int x : v) std::cout << x << ' ';
// Different distribution: normal (bell curve)
std::normal_distribution<double> normal(0.0, 1.0); // mean=0, stddev=1
std::vector<double> samples(1000);
std::generate(samples.begin(), samples.end(), [&engine, &normal] {
return normal(engine);
});
}
Why not rand()?
- Poor statistical quality (short period, bad distribution)
- Shared global state — not thread-safe
- No control over distribution
<random>gives you proper distributions and thread-local engines
Functor-Based Generator
When a lambda captures too many variables, a functor class is cleaner:
#include <algorithm>
#include <vector>
class IdGenerator {
int next_id_;
int step_;
public:
IdGenerator(int start = 1000, int step = 10)
: next_id_(start), step_(step) {}
int operator()() {
int id = next_id_;
next_id_ += step_;
return id;
}
};
int main() {
std::vector<int> ids(5);
std::generate(ids.begin(), ids.end(), IdGenerator(1000, 10));
// ids: {1000, 1010, 1020, 1030, 1040}
}
Common Pitfalls
Empty container — nothing happens:
std::vector<int> v; // size 0
std::fill(v.begin(), v.end(), 42); // no-op — empty range
// Fix: resize first
v.resize(5);
std::fill(v.begin(), v.end(), 42); // now works
// Or use fill_n with back_inserter:
std::fill_n(std::back_inserter(v), 5, 42);
Wrong capture in generate — lambda doesn’t update outer state:
int counter = 0;
// Wrong: [=] captures by value — counter inside lambda doesn't update outer counter
std::generate(v.begin(), v.end(), [=] { return counter++; });
// All elements get 0 — counter is a local copy in each call
// Correct: [&] captures by reference
std::generate(v.begin(), v.end(), [&] { return counter++; });
// Elements get 0, 1, 2, 3, 4 ...
fill is faster than generate for constants:
// Slow: lambda call overhead per element
std::generate(v.begin(), v.end(), [] { return 42; });
// Fast: optimized to memset-like operation for trivial types
std::fill(v.begin(), v.end(), 42);
Key Takeaways
std::fill— same value everywhere; often optimizes tomemsetfor trivial typesstd::fill_n— same value for first N elements; works withback_inserterto appendstd::generate— calls a callable per element; use[&]capture for stateful generatorsstd::iota— sequential values with++; in<numeric>, not<algorithm>- Use
<random>withstd::mt19937and appropriate distributions — neverrand() - Resize or use
back_inserterbefore fill/generate — they don’t add elements, only write to existing positions
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Fill C++ containers with std::fill, std::generate, and std::iota. Covers fill_n, generate_n, random number generation wi… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- C++ Algorithm Reverse | reverse·rotate·reverse_copy 완벽 정리
- C++ Algorithm Count | ‘카운트 알고리즘’ 가이드
- C++ Algorithm Remove | ‘제거 알고리즘’ 가이드
이 글에서 다루는 키워드 (관련 검색어)
C++, Algorithm, generate, fill, STL 등으로 검색하시면 이 글이 도움이 됩니다.