std::generate, 지역 정적 변수 (Local Static Variables)
개요
std::generate
는 C++ 표준 라이브러리의 <algorithm>
헤더에 포함된 함수로, 지정된 범위의 모든 요소에 특정 함수(제너레이터)를 호출하여 반환된 값을 채워 넣는 역할을 합니다. 이 과정에서 제너레이터 함수 내부에 지역 정적 변수(Local Static Variables)를 활용하면, 함수 호출 간에 상태를 유지해야 하는 경우 매우 유용합니다.
본 문서에서는 std::generate
를 사용하여 벡터를 임의의 값으로 채우는 예제를 통해, 제너레이터 함수 내에서 지역 정적 변수가 어떻게 상태를 보존하고 효율적인 코드 작성에 기여하는지 설명합니다.
C++ 버전별 주요 키워드 도입 시기
- C++98:
std::generate
,static
(지역 변수) - C++11:
auto
,constexpr
,<random>
헤더 (std::random_device
,std::mt19937
,std::uniform_int_distribution
),std::int32_t
등 고정 너비 정수 타입 - C++14: 숫자 구분자 (Digit Separator) - 예:
1'000'000U
내용 설명
std::generate
std::generate
함수는 시작 반복자(first
)와 끝 반복자(last
)로 정의되는 범위 [first, last)
에, 인자 없는 제너레이터 함수 g
가 생성하는 값을 순차적으로 할당합니다.
void generate(ForwardIt first, ForwardIt last, Generator g);
지역 정적 변수 (Local Static Variables)
함수 내부에 static
키워드로 선언된 변수를 지역 정적 변수라고 합니다. 이 변수들은 다음과 같은 특징을 가집니다.
- 단 한 번의 초기화: 프로그램 실행 중 해당 변수의 선언문을 처음 만났을 때 단 한 번만 초기화됩니다.
- 생명 주기(Life Cycle): 프로그램이 시작될 때 생성되고 종료될 때 파괴됩니다. 즉, 함수 호출이 끝나도 값이 소멸되지 않고 유지됩니다.
- 범위(Scope): 변수가 선언된 함수 블록 내에서만 접근할 수 있습니다.
예제 코드의 gen
함수에서 seed
, g
, d
는 모두 지역 정적 변수입니다. 이 덕분에 gen
함수가 여러 번 호출되더라도 난수 생성기와 분포 객체가 반복적으로 생성 및 초기화되는 오버헤드를 피할 수 있습니다. 상태가 유지되므로 매번 다른 난수를 효율적으로 생성할 수 있습니다.
예제 코드
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <random>
#include <vector>
namespace
{
constexpr auto NUM_ELEMENTS = size_t{1'000'000U};
}; // namespace
// 난수 생성을 위한 제너레이터 함수
std::int32_t gen()
{
// 지역 정적 변수: gen()이 처음 호출될 때 단 한 번만 초기화됩니다.
static auto seed = std::random_device{};
static auto g = std::mt19937{seed()};
static auto d = std::uniform_int_distribution<std::int32_t>{-10, 10};
return d(g);
}
// 벡터 내용을 출력하는 템플릿 함수
template <typename T>
void print_vector(const std::vector<T> &vec)
{
for (const auto val : vec)
{
std::cout << val << '\n';
}
std::cout << '\n';
}
int main()
{
auto my_vector = std::vector<std::int32_t>(NUM_ELEMENTS, 0U);
// my_vector의 시작부터 끝까지 gen() 함수가 반환하는 값으로 채웁니다.
std::generate(my_vector.begin(), my_vector.end(), gen);
// 생성된 벡터의 처음 10개 요소만 출력하여 확인합니다.
std::cout << "Generated first 10 elements:" << '\n';
for (size_t i = 0; i < 10; ++i)
{
std::cout << my_vector[i] << ' ';
}
std::cout << '\n';
return 0;
}
실행 결과
Generated first 10 elements:
-1 5 8 -4 10 2 -7 3 0 9
실행 시마다 결과는 달라질 수 있습니다.
활용팁
- 상태 유지:
std::generate
에 전달되는 제너레이터가 호출 횟수나 이전 값과 같은 상태를 기억해야 할 때 지역 정적 변수는 훌륭한 해결책입니다. 예를 들어,1, 2, 3, ...
과 같이 순차적으로 증가하는 값을 생성하는 제너레이터를 쉽게 만들 수 있습니다. - 성능 최적화: 난수 생성기, 파일 핸들, 데이터베이스 연결 등 생성 비용이 비싼 객체를 제너레이터 내에서 반복적으로 생성하지 않고
static
으로 선언하면 성능을 크게 향상시킬 수 있습니다. - 스레드 안전성(Thread-Safety): C++11부터 지역 정적 변수의 초기화는 스레드에 안전하게(thread-safe) 이루어집니다. 여러 스레드에서 동시에 제너레이터 함수를 호출하더라도 객체는 정확히 한 번만 초기화됩니다. 단, 초기화 이후 객체 자체에 대한 접근은 스레드에 안전하지 않을 수 있으므로 주의가 필요합니다. (예:
std::mt19937
은 스레드에 안전하지 않습니다.)
'개발 > C++ (98,03,11,14,17,20,23)' 카테고리의 다른 글
Modern C++ : Lambda Expressions (11, 14, 17, 20) (1) | 2025.09.08 |
---|---|
Modern C++ : std::numeric_limits (98, 11, 17) (0) | 2025.09.07 |
Modern C++ : std::chrono 날짜 및 시간대 (11, 14, 17, 20) (1) | 2025.09.06 |
Modern C++ : std::chrono 시간 측정 (11, 14, 17, 20) (0) | 2025.09.05 |
Modern C++ : std::mt19937 (11, 14, 17, 20) (0) | 2025.09.04 |
Modern C++ : std::filesystem (0) | 2025.09.03 |
Modern C++ : std::ostream & std::istream (98, 11, 17, 20) (0) | 2025.09.02 |
Modern C++ : std::string_view (17, 20) (1) | 2025.09.01 |