[C++] STL 개념 쉽게 이해하기

2022. 7. 20. 12:32♣ C++

 

STL 개념을 명확하게 이해하고 가봅시다.

자세한 예시보단 큰 틀을 파악하는 것을 우선으로 하는 포스팅입니다.

 

 

목차

📃 STL 개념

📃 STL 컨테이너

📃 STL 반복자

📃 STL 알고리즘

 

 

 

 

STL 개념

 

📌 개념

 

STL(Standard Template Library).

STL은 데이터 저장, 접근, 알고리즘 실행을 쉽고 빠르게 하는 하나의 틀입니다. 

비슷한 데이터를 한데 묶을 수 있게 하며(데이터 추상화), 그 데이터를 대상으로 특정 알고리즘을 언제 어디서든 계속 수행할 수 있도록(코드 재사용) 합니다.

 

 

 

 

 

📌 일반화 프로그래밍

 

C++가 가지는 주요 특징 중 하나가 일반화 프로그래밍입니다. 데이터를 중심으로 돌아가는 객체 프로그래밍과 달리 일반화 프로그래밍은 알고리즘을 중심으로 돌아갑니다. 

 

어떤 데이터가 오든 간에

 

일반화 프로그래밍의 일반화 대상은 데이터 타입입니다. 어떤 데이터 타입이 오든, 미리 정의해둔 알고리즘이 실행될 수 있도록 합니다. 코드 재활용이 가능하며, 알고리즘을 더욱 편리하게 활용할 수 있게 됩니다.

STL은 일반화 프로그래밍을 실현시킨 것입니다. 어떤 데이터 타입이 오든 알고리즘을 실행시킬 수 있습니다. 

 

 

 

📌 STL 구성

 

(1) STL 컨테이너: 알고리즘의 대상이 되는 데이터/ 객체를 저장하는 집합

(2) STL 반복자: 컨테이너 안의 요소에 접근할 수 있도록 하는 객체

(3) STL 알고리즘: 알고리즘에 대한 효율적인 구현 제공

 

 



 

STL 컨테이너

 

📌 개념

 

컨테이너(Container)는 같은 타입의 객체를 저장하는 집합입니다.

클래스 템플릿으로, 컨테이너를 선언할 때 요소의 타입을 명시할 수 있습니다. 

밑의 예시를 보면 알 수 있겠지만, 그리 거창한 개념이 아닙니다. python, java에선 너무나 일반적인 자료형들입니다. C++은 밑바닥에서부터 구현하다 보니 이런 자료형들을 직접 구현하려면 시간도 오래 걸리고 그에 따른 비용도 많이 소모됩니다. 그에 따른 Library라고 생각하시면 편합니다.

 

 

📌 종류

 

(1) 시퀀스 컨테이너 : 데이터를 선형으로 저장하는 컨테이너

EX) vector, deque, list, forward_list

 

(2) 연관 컨테이너 : 데이터를 일정 규칙에 따라 조직화하여 저장/관리하는 컨테이너

EX) set, multiset, map, multimap

 

(3) 컨테이너 어댑터 : 간결함/명료성을 위해 일부 기능을 제한한 시퀀스/연관 컨테이너의 변형.

단, 반복자를 지원하지 않으므로, STL 알고리즘을 적용할 순 없습니다.

 

 

 

📌 예시

  • 시퀀스 컨테이너 - vector
#include <iostream>
#include <string.h>
#include <string>
#include <iterator>
#include <vector>
using namespace std;


int main(int argc, char *argv[])
{
	vector<int> v = {1,2,3,4,5};
    	v.push_back(1);
	v.push_front(10);
	return 0;
}

 

 

 

 

 

STL 반복자

 

📌 개념

 

STL 컨테이너에 저장된 요소를 반복적으로 순회하고, 요소에 접근하는 기능을 제공합니다.

템플릿이 데이터 타입에 상관없이 알고리즘을 표현하듯이, 반복자는 컨테이너에 상관없이 알고리즘을 표현합니다. 즉, 어떤 컨테이너든 같은 반복자를 쓸 수 있다는 뜻입니다.

* 알고리즘 = 사용자가 원하는 프로세스

* 참조연산자(*), 대입/관계 연산자, 증가 연산자가 정의되어야 합니다. 

* 반복자는 포인터를 일반화한 것입니다. 포인터는 반복자가 가져야 할 모든 요구 사항을 만족합니다.

 

 

📌 종류

 

(1) 입력 반복자 : 컨테이너로부터 값을 읽는 기능을 제공합니다.

* 증가 연산자(++)를 사용하여 순방향 이동만 합니다. 참조 연산자(*) 사용해서 반복하여 참조 가능.

 

(2) 출력 반복자 : 컨테이너의 값을 변경하는 기능을 제공합니다.

* 증가 연산자(++)를 사용하여 순방향 이동만 합니다. 참조 연산자(*) 사용해서 단 한 번만 참조 가능.

 

(3) 순방향 반복자 : 입출력이 모두 가능한 반복자.

* 순방향 이동만 가능합니다. 참조 연산자(*) 사용해서 반복하여 참조 가능.

 

(4) 양방향 반복자 : 입출력 모두 가능하며, 양방향 이동이 가능합니다.

* 증가 연산자(++), 감소 연산자(--)를 사용하여 어디로든 이동 가능.

 

(5) 임의 접근 반복자 : 최상위 레벨의 반복자로서 많은 기능을 제공합니다.

* 첨자 연산자([])를 통해 임의의 요소에 접근 가능

 

(6) 기타 반복자 : 스트림 반복자/삽입 반복자/역방향 반복자/상수 반복자

 

 

 

📌 예시

  • 스트림 반복자 - ostream_iterator
#include <iostream>
#include <string.h>
#include <string>
#include <iterator>
#include <vector>
using namespace std;


int main(int argc, char *argv[])
{
	vector<int> v = {1,2,3,4,5};
    	copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
    
	return 0;
}



// 결과
1 2 3 4 5

 

 

 

 

 

STL 알고리즘

 

📌 개념

 

STL 알고리즘은 그저 알고리즘이다.

STL 컨테이너, 반복자를 활용하여 특정 프로세스를 수행하는 것을 말한다. 어떤 컨테이너가 오든 간에 수행할 수 있어야 한다. STL 컨테이너는 알고리즘을 제공하는 수많은 전역 함수와 함께 사용해야만 제 기능을 발휘할 수 있습니다. 

 

STL = STL 알고리즘 함수 + STL 컨테이너의 멤버 함수

 

알고리즘은 대부분 algorithm 헤더 파일, numeric 헤더 파일에 정의되어 있습니다.

 

 

 

📌 종류

 

(1) 읽기 알고리즘 : 지정된 범위에서 특정 데이터를 읽기만 하는 함수

EX) find(), for_each()

 

(2) 변경 알고리즘 : 컨테이너를 변경하진 않지만, 지정된 범위에서 요소의 값만 변경 가능

EX) copy(), swap(), transform()

 

(3) 정렬 알고리즘 : 지정된 범위의 요소들이 정렬되도록 컨테이너를 변경

EX) sort(), stable_sort(), binary_search()

 

(4) 수치 알고리즘 : 수치 관련 연산을 하는 알고리즘

EX) accumulate()

 

 

 

📌 함수 객체

 

STL 알고리즘은 그 자체로 기능을 수행하진 않습니다.

만약 정렬 알고리즘을 이용한다고 생각해보겠습니다. 어떤 방식으로 정렬할 것인지 정의해야 합니다. 오름차순으로 정렬할 것인가? 내림차순으로 정렬할 것인가?

STL 알고리즘을 실행하기 위해선 '어떻게'에 대한 정의가 이뤄져야 하며, 이 역할을 하는 것이 함수 객체입니다. STL 알고리즘엔 데이터를 전달함과 동시에 함수 객체를 전달합니다.  

* 함수 객체 뿐만 아니라, 함수 포인터/람다 표현식도 전달될 수 있습니다.

 

 

STL에선 함수 객체를 미리 정의하여 제공하고 있습니다.

* 참고 사이트

plus + greater >
minus - greater_equal >=
multiplies * less <
divides / less_equal <=
modulus % logical_and &&
negate - logical_or ||
equal_to == logical_not !
not_equal_to !=    

 

 

 

예시 - 함수 객체

  • plus - 덧셈
  • equal_to - 같은지 여부
  • greater_equal - 큰지 여부
#include <iostream>
#include <string.h>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <functional>
using namespace std;

int main(void)
{
    	plus<double> add;
	equal_to<double> comp;
	greater_equal<double> ge;
	
	cout << add(7.5, 3.45)<< endl;
	cout << comp(3.4, 7) << endl;
	cout << ge(1, 234.5)<< endl;
    	return 0;
}


// 결과
10.95
0
0

 

 

 

📌 예시

  • 정렬 알고리즘 - copy()
  • 함수 객체 - greater
#include <iostream>
#include <string.h>
#include <string>
#include <iterator>
#include <algorithm>
#include <vector>
using namespace std;


int main(int argc, char *argv[])
{
	vector<int> v = {1,2,3,4,5};
    v.push_back(1);
	v.push_back(10);
	
	cout << "정렬 전 : ";
	copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
	printf("\n");
	sort(v.begin(), v.end(), greater<int>());
	cout << "정렬 후 : ";
	copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
	return 0;
}


// 결과
정렬 전 : 1 2 3 4 5 1 10
정렬 후 : 10 5 4 3 2 1 1

 

정렬 알고리즘 sort()에 greater 함수 객체가 전달되었습니다. 이에 따라 내림차순으로 vector가 정렬된 것을 볼 수 있습니다.

 

 

지금까지 STL 개념과 약간의 예시를 살펴보았습니다. 

깊은 이해와 활용을 원한다면 각자의 구성(컨테이너, 반복자, 알고리즘) 별로 검색하며 공부하시길 바랍니다.