
본 글을 개인적 학습을 위한 글입니다. 틀린 내용이 있을 시 마구 지적해주시면 감사합니다.
오늘은 Standard Template Library에 대해 알아보는 시간을 갖겠습니다. 사실 이 STL은 짧게 다룰만한 주제는 아닙니다. 하지만, 분량 상 본 글에서는 압축하여 핵심만 살펴보도록 하겠습니다. STL은 가장 보편적이고 강력하게 쓰이는 C++의 기능으로써 아주 많은 자료구조와 알고리즘을 지원하고 있기 때문이죠. 이를 잘 활용한다면, C++을 더욱이 강력하게 사용할 수 있을 것입니다.
Standard Template Library(STL)은 C++에서 지원하는 표준 라이브러리 중 하나로 많은 제네릭 클래스와 제네릭 함수를 포함하고 있습니다.
주의 사항!
- 원하는 제네릭 클래스를 사용하려면 컨테이너 종류에 맞는 header를 선언해야 한다.
- 알고리즘(제네릭 함수)를 사용하려면 header를 선언해야 한다.
- STL이 선언된 namespace는 std이다.
순회자의 역할을 수행하는 iterator는 용도에 따라서 여러 가지로 사용할 수 있습니다. 용도에 알맞는 iterator를 사용하는 것도 매우 중요하다고 할 수 있죠.
iterator : 다음 element로 전진 (R/W)
const_iterator : 다음 element로 전진 (WO)
reverse_iterator : 지난 element로 후진 (R/W)
const_reverse_iterator : 지난 element로 후진 (WO)
vector는 가장 대표적인 제네릭 클래스입니다. 순차 자료 구조를 표방한 가변 길이 배열을 구현한 형태라고 할 수 있습니다. 원소의 저장, 삭제, 검색 등 다양한 멤버 함수를 지원하고 있고, 벡터에 저장된 원소는 순차 자료 구조와 마찬가지로 인덱스로도 접근할 수 있습니다. 참고로 인덱스는 동일하게 ‘0’ 부터 시작합니다. 하지만, 순차 자료 구조와 다르게 삽입과 삭제에 큰 도움을 가질 수 있습니다.

vector 클래스의 기본적인 사용법은 아래의 코드와 주석으로 살펴보겠습니다. (GPT의 도움을 받았습니다.)
#include <iostream>
#include <vector>
int main() {
// 벡터 생성 및 초기화
std::vector<int> vec = {1, 2, 3, 4, 5};
// 1. push_back() - 요소 추가
vec.push_back(6);
// 2. pop_back() - 마지막 요소 제거
vec.pop_back();
// 3. size() - 크기 확인
std::cout << "Size: " << vec.size() << std::endl;
// 4. at() - 특정 인덱스의 요소 접근
std::cout << "Element at index 2: " << vec.at(2) << std::endl;
// 5. front() & back() - 첫 번째 및 마지막 요소 접근
std::cout << "Front: " << vec.front() << ", Back: " << vec.back() << std::endl;
// 6. empty() - 벡터가 비어 있는지 확인
std::cout << "Is empty? " << (vec.empty() ? "Yes" : "No") << std::endl;
// 7. insert() - 특정 위치에 요소 삽입
vec.insert(vec.begin() + 1, 10);
// 8. erase() - 특정 요소 삭제
vec.erase(vec.begin() + 2);
// 9. clear() - 모든 요소 삭제
// vec.clear();
// 10. 반복자 사용 (begin(), end())
std::cout << "Vector elements: ";
for (auto it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
}
std::cout << std::endl;
return 0;
}
vector 클래스의 iterator는 글의 서두에서 설명했듯이, 반복자의 역할을 가집니다. 만일 STL을 공부 중이시라면 vector의 iterator만 알고 있으면, 다른 템플릿들을 사용하는 것에 무리가 없을 것이라고 생각합니다.
아래는 vector 클래스의 iterator를 선언하고 이에 벡터의 첫 주소를 부여하는 코드입니다.
vector<int> v; // v라는 이름의 vector 선언
vector<int>::iterator it; // iterator 선언
it = v.begin(); // it에 v의 시작 주소를 부여
이번에는 원소를 삭제하는 코드를 한번 보겠습니다.
it = v.erase(it); // it가 가리키는 위치의 원소를 제거하고 다음 원소에 대한 포인터를 return
당연히 다음 원소로 넘어가는 코드도 알아야 합니다. 하지만 놀랍게도 매우 간편하게 이동할 수 있습니다. 일반적인 포인터가 다음 주소로 이동하는 것과 같은 원리죠. 이 또한 Operator Overloading의 유용함이라고 알 수 있습니다.
it++; // 다음 주소로 이동
C++에는 컴파일러가 자동적으로 자료형을 찾아주는 기능이 존재합니다. 바로 auto 자료형입니다. 이는 사용자 정의 자료형의 배열을 순회할 때 자주 사용됩니다. 당연히 Primitives나 STL을 순회할 때도 가능하죠. 아래에서 간단한 이용법을 소개합니다.
for(auto e : v) { // vector v의 원소들을 차례대로 접근
cout << e << endl;
}
위의 예제는 앞의 글들에서는 설명하지 않았던, for-each 문입니다. 이는 조금 더 간편하게 반복문을 사용할 수 있다는 장점이 있지만, 수정은 불가한 즉 Read-Only의 성격을 가지고 있습니다.
글의 서두에서 설명했듯이, STL 자료 구조를 잘 활용하기 위한 템플릿 함수들이 존재합니다. 이 함수들을 사용하려면 #include <algorithm> 을 선언해야 합니다. 이 라이브러리를 사용하는 이유 중 하나는 바로 sort() 함수 때문일 것입니다. 아래에서 본 함수의 사용 사례와 함께 주석으로 살펴보겠습니다.
vector<int> v;
...
sort(v.begin(), v.begin() + 3); // 처음 3개 원소 정렬
sort(v.begin() + 2, v.begin() + 5);
// 벡터의 세 번째 원소에서 v.begin() + 4까지 3개의 원소 정렬
sort(v.begin(), v.end()); // 벡터 전체 정렬
오늘은 STL에 대해 아주 간략하게 알아보았습니다. STL은 C++의 대표 라이브러리로써 익히게 된다면 매우 유용하게 사용하고, 할 수 밖에 없을 것입니다. 이번 시리즈는 STL로써 마무리 짓도록 하겠습니다. The Programming Language C++ 시리즈는 제 개인적인 공부를 위해 작성되었고, 보완되어야 하는 점도 많습니다. 시리즈를 읽으실 때 가벼운 마음으로 읽어주시길 바라며, C++에 대한 추가적인 문서는 Effective C++과 함께 새로운 시리즈로써 작성될 것입니다. 감사합니다.