C++ STL (컨테이너와 반복자)

Seongcheol Jeon·2024년 11월 17일
0

CPP

목록 보기
22/47
post-thumbnail

표준 템플릿 라이브러리 (Standard Template Library, STL)는 표준 라이브러리의 일부로서 템플릿에 기반을 둔 컨테이너, 알고리즘, 반복자 등을 구현한 클래스와 함수를 가리키는 용어이다. 표준 템플릿 라이브러리를 사용하면 특정한 데이터 형식이나 알고리즘에 종속되지 않고 코드의 재사용성유연성을 높일 수 있다.

컨테이너란 무엇일까?

C++ 표준 템플릿 라이브러리를 왜 사용해야 하는지 묻는다면, 주저 없이 컨테이너라고 대답할 수 있다. C++언어를 사용하는 실제 개발 현장에서 컨테이너를 사용하지 않는 프로젝트는 아마도 찾아보기 힘들 것이기 때문이다.

컨테이너 (container)같은 타입의 여러 객체를 저장할 수 있는 묶음 단위의 데이터 구조이다. 쉽게 생각해서 단어 그대로의 의미인 컨테이너 상자 또는 마트에서 물건을 담는 쇼핑카라고 생각하면 된다.

컨테이너의 주 역할은 데이터를 저장하고 관리하며 저장된 원소에 접근할 수 있는 멤버 함수를 제공한다.

참고로 컨테이너는 한 가지 타입의 객체들만 보관할 수 있다.

반복자(iterator)란 무엇일까?

반복자 (iterator)객체지향 프로그래밍에서 배열 같은 컨테이너의 내부 원소들을 순회하는 객체이다. 반복자포인터와 비슷한 동작을 한다고 볼 수 있다.

표준 템플릿 라이브러리에서 모든 컨테이너는 각자의 반복자를 제공한다. 각 컨테이너의 반복자는 공통의 멤버 함수를 가지는데, 대표적으로 beginend가 있다. 반복자의 beginend 함수를 사용하는 예를 살펴보자.

#include <iostream>
#include <vector>


using namespace std;


int main()
{
    // vector 컨테이너 선언
    vector<int> vec;

    vec.push_back(0);
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    vec.push_back(4);

    // 반복자 it 선언과 동시에 vec의 시작 위치로 초기화.
    vector<int>::iterator it = vec.begin();

    cout << *it << endl;
    cout << *(it + 1) << endl;
    cout << *(it + 2) << endl;
    cout << *(it + 3) << endl;
    cout << *(it + 4) << endl;

    return 0;
}

실행 결과

0
1
2
3
4

begin 함수는 벡터의 첫 번째 원소에 접근할 수 있도록 위치를 반환해 준다.

반복자포인터(pointer)처럼 이해하면 쉽다!

begin 함수가 반환하는 반복자 it에 포인터처럼 역참조 연산자(*)를 이용하면 해당 원소에 접근할 수 있다. 따라서 *it, *(it + 1) 등의 코드는 벡터 컨테이너에 저장된 원소를 출력한다.

참고

반복자의 역참조 연산은 * 연산자 오버로딩을 통해 마치 포인터처럼 동작하게 만든 것이다.

다음의 코드는 반복자포인터와 같은 역할로 이해하면 좋은 예이다. 반복자에도 포인터처럼 증감 연산자를 사용할 수 있다.

#include <iostream>
#include <vector>


using namespace std;


int main()
{
    vector<int> vec;

    for (int i = 0; i < 5; i++) {
        vec.push_back(i);
    }

    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
        cout << *it << endl;
    }

    return 0;
}

실행 결과

0
1
2
3
4

두 번째 반복문을 보면 반복자 it를 를 선언하면서 vec.begin() 함수를 호출해 vec시작 위치로 초기화한다. 그리고 vec 컨테이너를 한 칸씩 순회하면서 원소를 출력(*it)한다. 이때 it++처럼 반복자에 증감 연산자를 사용할 수 있다.

한 가지 짚고 넘어갈 것은 end()함수가 가리키는 위치이다. end()함수는 컨테이너에 저장된 맨 마지막 원소의 바로 다음 위치를 반환한다.

다음 그림처럼 end()가 가리키는 반복자를 past-the-end 반복자 라고 부른다. 이는 맨 마지막 원소를 지나친 반복자라는 의미이다.

만약 컨테이너가 빈 상태라면 해당 컨테이너의 begin()end()같은 위치를 가리킨다.

반복자를 사용하면 어떤 컨테이너에 접근하든지 같은 방법으로 접근할 수 있다. 이것은 컨테이너알고리즘을 함께 사용할 수 있도록 반복자가 중간자 역할을 할 수 있다는 의미이다.

표준 템플릿 라이브러리에서 모든 컨테이너는 자신만의 반복자를 제공하는데, 컨테이너의 특성에 따라 각각의 반복자가 사용할 수 있는 연산과 함수가 다르다.

정리

반복자는 컨테이너에 저장된 원소에 효과적으로 접근할 수 있는 도구라고 생각할 수 있다. 배열이나 리스트와 같은 컨테이너에 저장된 원소를 한번에 하나씩 접근할ㄷ 수 있게 해주는 역할이라고 보면 된다.

반복자의 가장 큰 장점컨테이너의 내부 정보를 외부에 노출시키지 않고도 원소에 접근할 수 있다는 것이다. 덕분에 컨테이너의 내부 구현 방식이 변경되더라도 코드를 수정할 필요 없이 반복자를 통해 원소에 접근할 수 있다.

반복자는 벡터, 리스트, 큐처럼 선형 컨테이너에 적합하지만, 특정 조건을 만족하지 않을 때는 사용하기 어려울 수도 있다. 예를 들어 뒤로 이동할 수 없는 컨테이너나 무한한 개수의 원소를 가진 컨테이너에는 반복자를 사용할 수 없다. 따라서 반복자를 사용하기 전에 컨테이너의 특성과 반복자의 제약을 꼭 고려해야 한다.

0개의 댓글