C++ STL: 9장 - STL 내부 구현 심화

2025. 2. 26. 18:18프로그래밍 언어/C++ STL

9.1 STL의 템플릿 메커니즘

STL은 템플릿을 기반으로 설계된 라이브러리로, 일반화 프로그래밍(Generic Programming)의 철학을 실현합니다. 이 장에서는 STL의 템플릿 메커니즘과 이를 활용한 고급 기법을 다룹니다.

9.1.1 템플릿 메타프로그래밍 (Template Metaprogramming)

템플릿 메타프로그래밍은 컴파일 타임에 코드 생성을 수행하는 기법으로, STL 내부에서 자주 활용됩니다.

예제: 컴파일 타임 팩토리얼 계산

#include <iostream>

template <int N>
struct Factorial {
    static constexpr int value = N * Factorial<N - 1>::value;
};

template <>
struct Factorial<0> {
    static constexpr int value = 1;
};

int main() {
    std::cout << "Factorial of 5: " << Factorial<5>::value << "\n";
    return 0;
}

Note: STL 내부에서는 이와 같은 메타프로그래밍을 통해 데이터 구조와 알고리즘을 효율적으로 구현합니다.

9.1.2 SFINAE와 개념(Concepts)

  • SFINAE (Substitution Failure Is Not An Error):
    • 템플릿 매개변수의 타입에 따라 특정 템플릿을 선택적으로 활성화합니다.

예제:

#include <iostream>
#include <type_traits>

template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
increment(T value) {
    return value + 1;
}

int main() {
    std::cout << increment(5) << "\n";  // 정수 허용
    // std::cout << increment(5.5) << "\n";  // 컴파일 에러
    return 0;
}
  • Concepts (C++20):
    • SFINAE의 복잡함을 해결하기 위해 도입된 간단한 구문으로, 템플릿의 타입 제약을 명확히 정의합니다.

예제:

#include <iostream>
#include <concepts>

template <std::integral T>
T increment(T value) {
    return value + 1;
}

int main() {
    std::cout << increment(10) << "\n";
    // std::cout << increment(3.5) << "\n";  // 컴파일 에러
    return 0;
}

9.2 STL의 메모리 관리

9.2.1 할당자(Allocator)의 역할

STL 컨테이너는 사용자 정의 할당자를 통해 메모리 관리 방식을 커스터마이징할 수 있습니다. 이는 메모리 제한 환경이나 특수 목적의 메모리 관리에 유용합니다.

예제:

#include <iostream>
#include <vector>
#include <memory>

int main() {
    std::vector<int, std::allocator<int>> vec = {1, 2, 3};

    for (int n : vec) {
        std::cout << n << " ";
    }

    return 0;
}

9.2.2 메모리 풀이 STL 컨테이너에 미치는 영향

  • 메모리 풀은 할당/해제 비용을 줄이고 성능을 최적화하는 데 유용합니다.
  • STL 컨테이너는 커스텀 메모리 풀이 제공하는 할당자를 활용할 수 있습니다.

예제:

#include <iostream>
#include <vector>
#include <memory_resource>

int main() {
    char buffer[1024];
    std::pmr::monotonic_buffer_resource pool{buffer, sizeof(buffer)};
    std::pmr::vector<int> vec{&pool};

    vec.push_back(1);
    vec.push_back(2);

    for (int n : vec) {
        std::cout << n << " ";
    }

    return 0;
}