Programming/C, C++

[C++]컨테이너(Container)와 이터레이터(Iterator) 기초 2

변화의 물결1 2025. 5. 23. 19:15

 

 

안녕하세요

 

 지난 글에는 C++의 컨테이너와 이터레이터가 무엇인지, 어떻게 사용하는지에 대해 알아보았습니다.  이번에는 조금 컨테이너와 이터레이터가 내부적으로 어떻게 동작하는 알아보겠습니다.

 


 

1. 컨테이너에 [] 연산자 사용

 

 std::vector를 사용할 때, 우리는 배열처럼 v[i] 형태로 특정 위치의 요소에 매우 편리하게 접근할 수 있습니다.

 

  이유는 연산자 오버로딩(Operator Overloading) 때문입니다. []는 C++ 클래스에서 특별한 함수(멤버 함수)로 직접 구현할 수 있는 연산자 중 하나입니다.

 

 원리를 확인하기 위해, std::vector를 아주 간단하게 흉내 낸 ThingVector라는 클래스를 만들어 보겠습니다.

 

 

template<typename T>
class ThingVector {
private:
    T data[100]; // 설명을 위해 고정 크기 배열 사용
    int iBegin;
    int iEnd;

public:
    ThingVector() : iBegin(0), iEnd(0) {}

    // ... (다른 함수들) ...

    // [] 연산자를 멤버 함수로 구현 (오버로딩)
    T& operator[](int index) {
        return data[index];
    }
};

 

 위 코드에서 operator [] 함수 사용해서 v[5]와 같은 코드를 사용할 수 있습니다. 이 코드는 내부적으로 v.operator[](5)를 호출하는 것과 같습니다.

 

 왜 반환 타입이 T가 아니라 T&(참조, Reference)을 한 것은 만약 T로 반환하면 값을 읽을 수만 있습니다 (int a = v[0];).

 

 하지만 T&로 반환하면 해당 메모리 공간 자체를 가리키게 되므로, 값을 읽는 것은 물론 값을 수정하는 것도 가능합니다. (v[0] = 100;).

 

 

2. 이터레이터(Iterator) 기능 추가

 

 모든 컨테이너가 [] 연산자를 지원하지는 않습니다. 예를 들어, std::list는 요소들이 메모리에 연속적으로 저장되어 있지 않기 때문에, i번째 요소에 한 번에 접근하는 것이 비효율적입니다.

 

 그래서 이터레이터라는 통일된 접근 방식이 필요합니다. 이제 ThingVector에 이터레이터 기능을 추가해 보겠습니다.

 

 이터레이터의 실제 구현은 복잡한 구조체(struct)이지만, 그 핵심 개념은 "컨테이너 속 요소를 가리키는 포인터"입니다. ThingVector는 내부적으로 배열을 사용하므로, 이 개념을 실제 포인터를 사용하여 간단하게 구현해 볼 수 있습니다.

 

 

template<typename T>
class ThingVector {
public:
    // 외부에서 ThingVector<int>::iterator 처럼 접근해야 하므로 public에 둡니다.
    typedef T* iterator;

private:
    T data[100];
    int iBegin;
    int iEnd;

public:
    // ... (생성자, operator[] 등) ...

    iterator begin() {
        return &data[iBegin];
    }

    iterator end() {
        return &data[iEnd];
    }
};

 

 

코드를 간략하게 보자면,

 

1) typedef T* iterator;

    ThingVector의 이터레이터는 "T 타입 데이터의 포인터(T*)"와 같다고 iterator라는 별명을 붙여준 것입니다. 이렇게 하면 ThingVector<int>::iterator는 int*와 같은 타입이 됩니다.

 

 2) iterator begin()

    컨테이너의 첫 번째 요소(data[0])의 메모리 주소를 반환합니다.

 3) iterator end()

    컨테이너의 마지막 요소 바로 다음(data[iEnd])의 메모리 주소를 반환합니다.

 

 

3. 전체 코드를 통해 동작 확인

 

 ThingVector 클래스 사용하는 전체 예제 코드를 통해 우리가 만든 [] 연산자와 이터레이터가 어떻게 동작하는지 확인해 봅시다.

 

 

#include <iostream>
// #include <vector>

template<typename T>
class ThingVector {
public:
    // 이터레이터 타입을 T에 대한 포인터로 정의
    typedef T* iterator;

private:
    T data[100]; // 간단한 설명을 위해 고정 크기 배열 사용
    int iBegin;
    int iEnd;

public:
    ThingVector() {
        iBegin = 0;
        iEnd = 0;
    }

    void push_back(T _data) {
        data[iEnd] = _data;
        iEnd += 1;
    }

    // [] 연산자 오버로딩. T&를 반환하여 읽기/쓰기 모두 가능하게 함
    T& operator[](int index) {
        return data[index];
    }

    int size() const {
        return iEnd - iBegin;
    }

    iterator begin() {
        return &data[iBegin];
    }

    iterator end() {
        return &data[iEnd];
    }
};

int main()
{
    // std::vector 대신 만든 ThingVector 사용
    ThingVector<int> v;
    v.push_back(4);
    v.push_back(7);
    v.push_back(9);
    v.push_back(1);
    v.push_back(3);

    // 방법 1: [] 연산자로 요소 접근
    printf("--- Access with [] operator ---\n");
    for (int i = 0; i < v.size(); i++)
    {
        printf("%d\n", v[i]); // 내부적으로 v.operator[](i) 호출
    }

    printf("------------\n");

    // 방법 2: 이터레이터로 요소 접근 (어떤 컨테이너든 일관된 방식)
    printf("--- Access with iterator ---\n");
    ThingVector<int>::iterator it;
    for (it = v.begin(); it != v.end(); ++it)
    {
        // it는 포인터이므로, *it를 통해 실제 값을 가져옴
        const int iNumber = *it;
        printf("%d\n", iNumber);
    }

    return 0;
}

  

 

< 실행 결과 >

 

[] 연산자와, iterator 타입을 이용해서도 잘 작동하는 것을 확인할 수 있습니다.

 

 

 

4. 정리해 보기

 

 - [] 접근은 연산자 오버로딩이라는 C++ 문법을 통해 구현가능합니다.

 - 이터레이터(iterator)는 포인터와 유사하게 동작하며, begin()과 end() 함수를 통해 컨테이너의 모든 요소를 일관된 방식으로 순회할 수 있게 해 줍니다. (컨테이너와 이터레이터는 C++ STL의 핵심요소 중 하나)

 

 위의 내용으로 원리에 대해서 알아보았지만, 실제 std::vector와 같은 STL 컨테이너들은 메모리 관리, 예외 처리 등 훨씬 더 효율적으로 구현되어 있습니다.

 

 원리를 조금 알고 사용하면 더 좋지 않을까 합니다.

 

 

 감사합니다.

 

 

<참고 자료>

1. C++ Understanding: 고급 Advanced

https://www.youtube.com/playlist?list=PLrrTotxaO6khn83BjtBN-1HMDc9MZ__yt

2. Effective Modern 이펙티브 모던 C++, Book

 

반응형