C++ STL: 5장 - STL과 메모리 관리

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

5.1 메모리 관리의 기본

STL은 효율적인 메모리 관리를 위해 std::allocator를 기본 메모리 할당자로 사용합니다. 컨테이너들은 이를 통해 자동으로 메모리를 할당하고 해제하며, 개발자가 직접 메모리를 관리할 필요가 없습니다.

5.2 메모리 관리 방식

5.2.1 동적 메모리 관리

#include <vector>
#include <iostream>

int main() {
    std::vector<int> numbers;

    // 미리 메모리 할당
    numbers.reserve(10);

    for (int i = 0; i < 10; ++i) {
        numbers.push_back(i);
        std::cout << "Size: " << numbers.size() 
                  << ", Capacity: " << numbers.capacity() << "\n";
    }
}

5.2.2 자동 메모리 해제

void example() {
    std::vector<int> numbers = {1, 2, 3};
    // 함수 종료 시 자동으로 메모리 해제
}

5.3 사용자 정의 메모리 할당자

STL은 기본적으로 std::allocator를 사용하지만, 사용자 정의 메모리 할당자를 만들어 특정 요구에 맞게 메모리 동작을 변경할 수 있습니다.

5.3.1 기본 할당자의 구조

  • std::allocator는 다음과 같은 메서드를 제공합니다:
    • allocate: 메모리를 할당합니다.
    • deallocate: 메모리를 해제합니다.
    • construct: 객체를 생성합니다.
    • destroy: 객체를 소멸시킵니다.

5.3.2 커스텀 할당자 구현

사용자 정의 메모리 할당자를 구현하려면 std::allocator를 상속하거나 직접 메서드를 정의해야 합니다.

예제:

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

template <typename T>
class CustomAllocator {
public:
    using value_type = T;

    CustomAllocator() {}
    template <typename U>
    CustomAllocator(const CustomAllocator<U>&) {}

    T* allocate(std::size_t n) {
        std::cout << "Allocating " << n << " elements\n";
        return static_cast<T*>(::operator new(n * sizeof(T)));
    }

    void deallocate(T* p, std::size_t n) {
        std::cout << "Deallocating " << n << " elements\n";
        ::operator delete(p);
    }
};

int main() {
    std::vector<int, CustomAllocator<int>> vec;
    vec.push_back(1);
    vec.push_back(2);

    return 0;
}

5.4 메모리 최적화 기법

5.4.1 메모리 예약

std::vector<int> numbers;
numbers.reserve(1000);  // 1000개 요소를 위한 메모리 미리 확보

5.4.2 메모리 줄이기

std::vector<int> numbers(1000);
numbers.resize(100);      // 크기를 100으로 줄임
numbers.shrink_to_fit(); // 여분의 메모리 반환

5.4.3 move 활용

std::vector<std::string> source = {"Hello", "World"};
std::vector<std::string> dest = std::move(source); // 메모리 복사 없이 이동

5.5 메모리 관리

  1. 메모리 할당 비용: 메모리 할당과 해제는 비용이 크므로 최소화해야 합니다.
  2. 소멸자 호출: 컨테이너를 직접 삭제하지 말고 범위를 벗어나게 하여 소멸자가 호출되도록 해야 합니다.
  3. 컨테이너 복사: 큰 컨테이너를 복사할 때 불필요한 메모리 사용이 발생할 수 있으므로 주의해야 합니다.
  • 크기를 알 수 있다면 미리 reserve
std::vector<int> numbers;
numbers.reserve(expectedSize);  // 재할당 횟수 감소
  • 임시 객체는 이동 연산자 활용
std::vector<std::string> getStrings() {
    std::vector<std::string> temp = {"A", "B", "C"};
    return temp;  // 이동 연산자가 호출됨
}
  • 불필요한 메모리는 즉시 반환
std::vector<int> numbers(1000);
// 작업 수행 후
numbers.clear();
numbers.shrink_to_fit();

 

성능 최적화 예시

1. 벡터 크기 최적화

std::vector<int> efficient;
efficient.reserve(1000);  // 한 번의 할당

std::vector<int> inefficient;
for (int i = 0; i < 1000; ++i) {
    inefficient.push_back(i);  // 여러 번 재할당 발생
}

2. 메모리 재사용

std::vector<int> numbers;
numbers.reserve(100);

// 반복적인 작업에서 재사용
for (int iteration = 0; iteration < 10; ++iteration) {
    numbers.clear();  // 메모리는 유지하고 크기만 0으로
    // 새로운 데이터로 채움
}

 

STL은 메모리 관리를 자동화하여 프로그래머가 메모리 누수를 걱정하지 않도록 설계되었습니다. 기본 제공되는 std::allocator는 대부분 효율적이지만, 필요에 따라 커스텀 할당자를 구현 메모리 관리 방식을 최적화할 수 있다.