프로그램에 필요한 자료구조와 알고리즘을 템플릿으로 제공하는 C++ 표준 라이브러리.
STL의 구성 요소로 컨테이너, 반복자, 알고리즘, 함수 객체, 어댑터, 할당기가 있음.
객체를 저장하는 객체로서 자료구조라고도 함.
컨테이너의 원소를 가리키며, 포인터와 비슷한 개념.
삭제, 검색, 연산 등을 해결하는 일반화된 방법을 제공하는 함수 템플릿.
함수처럼 동작하는 객체로서 () 연산자를 오버로딩한 객체.
구성 요소의 인터페이스를 변경.
컨테이너의 메모리 할당 정책을 캡슐화한 클래스 객체.
컨테이너는 자신만의 기본 할당기를 가지고 있으며, 대부분의 프로그램에서는 기본 할당기만으로 충분.
객체를 저장하는 자료구조
컨테이너에 원소가 삽입되는 순서대로 저장됨. (선형적)
Ex) vector, list, deque
컨테이너에 원소가 삽입되는 순서에 상관없이, 특정 정렬 기준에 따라 저장됨. (비선형적)
Ex) set, multiset, map, multimap
데이터 여러 개가 하나의 연속된 메모리에 저장됨.
Ex) vector, deque
데이터 하나를 하나의 메모리 단위에 저장.
Ex) list, set, multiset, map, multimap
컨테이너의 원소를 가리키는 포인터처럼 동작하며, 컨테이너 원소를 순회하고 접근하는 일반화된 방법을 제공.
- 컨테이너 내부의 원소(객체)를 가리키고 접근 가능해야 함. (*연산자 제공)
- 다음 원소로 이동하고 컨테이너의 모든 원소를 순회할 수 있어야 함. (++, !=, == 연산자 제공)
현 위치의 원소를 한번만 읽을 수 있는 반복자
현 위치의 원소를 한번만 쓸 수 있는 반복자
입력, 출력 반복자 기능에 순방향(++)으로 이동이 가능한 반복자.
순방향 반복자 기능에 역방향(--)으로 이동이 가능한 반복자
양방향 반복자 기능에 +, -, +=, -=, [] 연산이 가능한 반복자.
컨테이너 원소의 순서있는 집합.
컨테이너의 반복자를 사용하여 원소들을 출력하는 예제.
#include <iostream>
#include <vector> // vector 컨테이너 사용.
using namespace std;
int main()
{
vector<int> v; // vector<int> 컨테이너 v 생성.
v.push_back(10); // v의 맨 뒤에 "10" 데이터 추가.
v.push_back(20); // v의 맨 뒤에 "20" 데이터 추가.
v.push_back(30); // v의 맨 뒤에 "30" 데이터 추가.
v.push_back(40); // v의 맨 뒤에 "40" 데이터 추가.
v.push_back(50); // v의 맨 뒤에 "50" 데이터 추가.
vector<int>::iterator iter; // vector<int> 컨테이너 반복자 생성.
for (iter = v.begin(); iter != v.end(); iter++)
{
cout << *iter << endl; // 반복자가 현재 가리키는 원소 반환.
}
return 0;
}
순차열의 원소를 조사, 변경, 관리, 처리할 목적으로 사용.
특정 컨테이너나 원소 타입에 상관없이 사용 가능.
순차열에서 특정 조건에 맞는 원소를 찾음.
찾은 경우 해당 원소의 위치를 반환, 못 찾은 경우 순차열의 마지막(end()) 위치를 반환.
순방향 반복자를 요구하기 때문에, 순방향 반복자를 지원하는 컨테이너라면 find 알고리즘 사용 가능.
#include <iostream>
#include <vector> // vector 컨테이너 사용.
#include <algorithm> // 알고리즘 사용.
using namespace std;
int main()
{
vector<int> v; // vector 컨테이너 v 생성.
v.push_back(10); // v의 맨 뒤에 "10" 데이터 추가.
v.push_back(20); // v의 맨 뒤에 "20" 데이터 추가.
v.push_back(30); // v의 맨 뒤에 "30" 데이터 추가.
v.push_back(40); // v의 맨 뒤에 "40" 데이터 추가.
v.push_back(50); // v의 맨 뒤에 "50" 데이터 추가.
vector<int>::iterator iter; // 반복자 생성.
iter = find(v.begin(), v.end(), 20); // 순차열에서 20 찾기.
cout << *iter << endl; // 현재 반복자가 가리키는 원소(20) 출력.
iter = find(v.begin(), v.end(), 314); // 순차열에서 314 찾기.
if (iter == v.end()) // 못찾으면 순차열의 마지막을 반환.
cout << "못찾음" << endl;
return 0;
}
클라이언트가 정의한 동작을 다른 구성 요소에 반영하려 할 때 사용.
많은 STL 알고리즘들이 함수 객체, 함수, 함수 포인터 등의 함수류를 인자로 받아 알고리즘을 유연하게 동작시킴.
- less : (<) 기준으로 원소 정렬. (오름차순)
- greater : (>) 기준으로 원소 정렬. (내림차순)
sort 알고리즘(정렬)에 less, greater 함수 객체 적용.
sort 알고리즘에 함수 객체 미사용시, less를 기본적으로 사용.
#include <iostream>
#include <vector> // vector 컨테이너 사용.
#include <algorithm> // 알고리즘 사용.
using namespace std;
int main()
{
vector<int> v; // vector 컨테이너 v 생성.
v.push_back(50); // v의 맨 뒤에 "50" 데이터 추가.
v.push_back(10); // v의 맨 뒤에 "10" 데이터 추가.
v.push_back(30); // v의 맨 뒤에 "30" 데이터 추가.
v.push_back(20); // v의 맨 뒤에 "20" 데이터 추가.
v.push_back(40); // v의 맨 뒤에 "40" 데이터 추가.
vector<int>::iterator iter; // 반복자 생성.
sort(v.begin(), v.end(), less<int>()); // v의 원소 오름차순 정렬.
for (iter = v.begin(); iter != v.end(); iter++) // v의 원소들 출력.
{
cout << *iter << endl;
}
cout << endl;
sort(v.begin(), v.end(), greater<int>()); // v의 원소 내림차순 정렬.
for (iter = v.begin(); iter != v.end(); iter++) // v의 원소들 출력.
{
cout << *iter << endl;
}
return 0;
}
구성요소의 인터페이스를 변경.
일반 컨테이너를 다른 방식의 컨테이너로 변경.
Ex) stack, queue, priority-queue
기본 stack 컨테이너 사용하기.
#include <iostream>
#include <stack> // stack 컨테이너 사용.
using namespace std;
int main()
{
stack<int> st; // stack 컨테이너 st 생성.
st.push(10); // stack에 데이터 "10" 추가.
st.push(20); // stack에 데이터 "20" 추가.
st.push(30); // stack에 데이터 "30" 추가.
cout << st.top() << endl; // stack의 가장 위에 있는 값 출력.
st.pop(); // stack의 가장 위에 있는 값 삭제.
cout << st.top() << endl; // stack의 가장 위에 있는 값 출력.
st.pop(); // stack의 가장 위에 있는 값 삭제.
cout << st.top() << endl; // stack의 가장 위에 있는 값 출력.
st.pop(); // stack의 가장 위에 있는 값 삭제.
if (st.empty()) // stack이 비어있는지 확인.
cout << "데이터 없음" << endl;
return 0;
}
vector 컨테이너를 stack 컨테이너로 변경하기.
#include <iostream>
#include <vector> // vector 컨테이너 사용.
#include <stack> // stack 컨테이너 사용.
using namespace std;
int main()
{
stack<int, vector<int>> st; // vector컨테이너를 stack 컨테이너로 변경한 st 생성.
st.push(10); // stack에 데이터 "10" 추가.
st.push(20); // stack에 데이터 "20" 추가.
st.push(30); // stack에 데이터 "30" 추가.
cout << st.top() << endl; // stack의 가장 위에 있는 값 출력.
st.pop(); // stack의 가장 위에 있는 값 삭제.
cout << st.top() << endl; // stack의 가장 위에 있는 값 출력.
st.pop(); // stack의 가장 위에 있는 값 삭제.
cout << st.top() << endl; // stack의 가장 위에 있는 값 출력.
st.pop(); // stack의 가장 위에 있는 값 삭제.
if (st.empty()) // stack이 비어있는지 확인.
cout << "데이터 없음" << endl;
return 0;
}
일반 반복자의 동작 방식을 변경.
Ex) reverse_iterator, back_insert_iterator, front_insert_iterator, insert_iterator
reverse_iterator를 사용하여, vector의 일반 반복자를 역방향 반복자로 변경하기.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
// 일반 반복자. (순방향 반복자)
for (vector<int>::iterator iter = v.begin(); iter != v.end(); iter++)
{
cout << *iter << endl;
}
cout << endl;
// 역방향 반복자.
vector<int>::reverse_iterator riter(v.rbegin()); // rbegin() 멤버 함수로 riter 초기화.
for (; riter != v.rend(); riter++) // rend() 멤버 함수로 역방향 반복자가 마지막 원소 판별.
{
cout << *riter << endl;
}
return 0;
}
역방향 반복자가 가리키는 실제 원소는, 현재 가리키고 있는 원소의 다음(++) 원소.
정방향 반복자를 역방향 반복자로 변경하여 사용할 때 호환성을 위해 이렇게 설계됨.
함수 객체의 동작 방식을 변경
Ex) 바인더, 부정자, 함수 포인터 어댑터
함수 어댑터 not2를 사용해서 이상 조건자 less 함수 동작 변경하기
#include <iostream>
#include <functional>
using namespace std;
int main()
{
// 임시 less 함수 객체 사용.
cout << less<int>()(10, 20) << endl;
cout << less<int>()(20, 20) << endl;
cout << less<int>()(20, 10) << endl;
cout << "==============" << endl;
// 임시 less 함수 객체에 not2 적용.
cout << not2(less<int>())(10, 20) << endl;
cout << not2(less<int>())(20, 20) << endl;
cout << not2(less<int>())(20, 10) << endl;
cout << endl;
// less 함수 객체 l 사용.
less<int> l;
cout << l(10, 20) << endl;
cout << l(20, 20) << endl;
cout << l(20, 10) << endl;
cout << "==============" << endl;
// less 함수 객체 l에 not2 적용.
cout << not2(l)(10, 20) << endl;
cout << not2(l)(20, 20) << endl;
cout << not2(l)(20, 10) << endl;
return 0;
}