본문 바로가기
C++/기초

C++ 기초 : STL (vector와 list)

글: 시플마 2024. 4. 20.

가변 배열을 직접 구현했었지만,

사실 표준 라이브러리에서 제공하는 가변 배열이 있습니다.

 

밑에 코드를 보시면

 

2번째 줄에서 "vector"를 포함시켜서 사용할 수 있습니다.

 

vector는 클래스 템플릿이기 때문에 

어떤 자료형을 관리하는 클래스를 만들 것인지

자료형을 명시해 줘야 합니다. 

 

그리고 std라는 namespace에 존재하기 때문에

범위 지정 연산자를 통해 std를 붙여줘야 하죠.

계속 붙여야 하는 것이 번거롭다면 main 함수 밖에

using std::vector; 코드를 추가하면 바로 사용할 수 있죠.

 

 

클래스 템플릿을 이용하여 vector<int>라는 클래스를 

만들고 이를 통해 객체 vecInt를 만들었습니다.

 

 

8 ~ 9번째 줄을 보면 데이터를 삽입하는 함수,

push_back을 사용할 수 있음을 알 수 있네요.

 

객체 vecInt를 통해 가리키고 있는 Heap 영역에

동적 할당된 공간에 10과 20이 차례대로 삽입되었을 겁니다.

 

 

13과 14번째 줄은 서로 같은 코드라고 봐도 됩니다.

vecInt가 가리키는 공간의 인덱스에 접근하는

at 함수가 있고 vecInt는 객체이지만 마치 배열처럼

사용할 수 있도록 [ ] 연산자를 제공하고 있죠.

 

아마 vector라는 클래스 내부에

[ ] 연산자가 오버로딩되어 있겠죠?

 

13 ~ 14번째 줄은 1번 인덱스,

즉 20이라는 값을 반환할 것입니다.

 

 

15번째 줄에 data 함수는 vecInt가 가리키는

공간(가변 배열)의 주솟값을 반환하는 함수입니다.

 

 

16번째 줄에 size 함수는 vecInt가 가리키는

공간(가변 배열)에 데이터를 몇 개 넣었는지

알려주는 함수입니다.

 

 

17번째 줄에 capacity 함수는 vecInt가 가리키는

공간(가변 배열)의 최대 개수를 반환하는 함수죠.

 

 

이러한 함수들도 물론

우리가 만든 가변 배열 클래스 템플릿에

추가해 줄 수 있겠죠?

 

20 ~ 22번째 줄은 

vector 클래스 템플릿의

data, size, capacity 함수를 구현한 모습입니다.

 

data 함수는 가변 배열의 주솟값을 반환하는 함수이므로

가변 배열 공간을 가리키는 멤버 m_pData를 반환하면 되죠.

 

가변 배열에 어떤 자료형의 데이터든 들어갈 수 있기 때문에 

이에 맞는 자료형으로 읽기 위해 T형 포인터를 반환 타입으로 설정합니다.

 

 

size 함수는 현재 가변 배열에 들어 있는

데이터의 개수를 나타내므로 m_iCount를 반환하면 됩니다.

 

 

capacity 함수는 현재 가변 배열의 최대 개수를

나타내는 함수이므로 m_iMaxCount를 반환하면 되죠.

 

 

 

 


 

 

 

 

 

마찬가지로 연결형 리스트도

표준 라이브러리에서 제공합니다.

 

3번째 줄처럼 list를 포함시킨 후 사용할 수 있습니다.

 

list 클래스 템플릿도 std라는 namespace에 있기 때문에

앞에 std::를 붙여서 사용해야 합니다. 이것이 번거롭다면

6번째 줄에서 보이는 것처럼 using 지시문에 list를 적으면

바로 사용할 수 있게 됩니다.

 

 

24 ~ 25번째 줄을 보시면

push_back과 push_front 함수를 제공하는 것이 보입니다.

연결형 리스트는 맨 앞이나 맨 뒤에 데이터를 삽입할 수 있습니다.

 

반면 가변 배열 역할을 하는 vector를 통해서는 

push_front 함수를 사용할 수 없죠. 배열로 이루어진 공간 맨 앞에

데이터를 삽입한다는 것은 상당히 비효율적이기 때문이죠.

 

새로 공간을 할당하고 맨 앞에 새로운 데이터를 삽입한 후,

기존 데이터를 새로운 공간에 복사해야 하는데 심지어 한 칸 뒤에

복사해야 하죠. 애초에 맨 앞에 데이터가 삽입될 일이 있다고

판단되면 vector라는 자료 구조를 사용하면 안되는 것이죠.

 

 

27번째 줄에서는 현재 연결형 리스트가 관리하는 노드의 개수, 

즉 데이터의 개수를 반환하는 함수 size가 보입니다.

 

size 함수를 연결형 리스트 역할을 하는

 

직접 만든 클래스 템플릿에도 추가해 주었습니다.

 

노드의 개수, 즉 데이터의 개수를 나타내는 멤버 iCount를 반환하면 되겠죠.

 

 

list에서는 capacity 함수가 제공되지 않습니다.

연결형 리스트에서는 데이터가 삽입되면 그때마다

노드를 만들어 데이터를 넣는 방식이므로

데이터가 들어갈 수 있는 공간의 개수가

최대 몇 개인지 알 필요가 없기 때문이죠.

 

또한 list에서는 [ ] 연산자를 오버로딩해 놓지 않았습니다.

[ ] 연산자를 통해 n번째 노드에 접근할 수 있게 

하면 사용자가 list를 배열로 오해할 수 있기 때문에

[ ] 연산자를 제공하지 않음으로써 list는

배열이 아님을 표현하고 있는 것이죠.

 

 


 

 

 

vecInt가 가리키는 가변 배열 안에 있는 값을

확인하고 싶으면 아래 코드와 같이

 

for 문을 사용하면 됩니다.

 

20번째 줄이나 21번째 줄의 코드처럼 [ ] 연산자를 통해

접근하거나 at 함수를 사용하여 접근하고 cout을 통해

값을 출력하면 됩니다.

 

이때 for 문에 사용되는 변수 i의 자료형이 size_t인데 

이는 long long 자료형이라고 생각하면 됩니다. 8Byte 정수죠.

typedef을 이용하여 size_t라는 이름을 사용할 뿐이죠.

 

size_t를 클릭 후 F12를 누르면

size_t의 정체를 확인할 수 있습니다. 

 

__int64라고 나오는데 long long이랑 같은 겁니다.

 

size_t를 사용하는 이유는

size 함수의 반환 타입이  size_t이므로 

자료형을 맞추기 위해 사용한 겁니다.

 

 

 

 


 

 

 

 

 

근데 객체 listInt 같은 경우에는 

가리키고 있는 공간이 배열이 아니고,

노드 형식으로 따로따로 있습니다.

배열처럼 연속적인 메모리 공간이 아니죠.

 

그렇기 때문에 리스트가 관리하는

데이터를 쭉 확인하려면 첫 번째 노드로 접근하고

해당 노드가 가리키는 다음 노드에 접근하고

다시 다음 노드의 다음 노드가 가리키는 노드에 접근해야 합니다.

 

게다가 첫 번째 노드에 접근하려면 멤버 변수의 이름을 알아야 하고,

다음 노드로 접근하기 위해 어떤 멤버 변수가 다음 노드를 가리키는

포인터인지, 노드는 어떤 클래스명을 가지고 있는지 

사용자가 파악해야 하는 것이 너무 많습니다.

 

 

그래서 데이터를 순회할 수 있는 반복자,

iterator라는 것을 제공합니다. 

 

아래 코드에서

 

30번째 줄을 보시면 list<int> 클래스 안에 있는

iterator라는 클래스로 iter라는 객체를 만들었습니다. 

 

이렇게 클래스 안에 클래스가 있는 구성을

'inner calss'라고 합니다. 

 

클래스 iterator로 만든 객체 iter에

첫 번째 노드의 주솟값을 반환하는 begin 함수를 이용하여

listInt의 첫 번째 노드의 주솟값을 저장합니다.

 

 

31번째 줄에서 변수 iData에

iter를 역참조하여 값을 대입하고 있습니다.

 

28번째 줄에서 push_front 함수를 통해

100을 대입하였으니 iter는 100이 들어 있는 

노드를 가리킬 것이고 iData에는 해당 노드를

역참조하여 얻은 값인 100이 대입되겠죠?

 

 

근데 객체 iter는 클래스 iterator로 만든 객체입니다.

포인터가 아니죠. 근데 사용할 때 * 연산을 사용하네요.

iterator 내부에는 * 연산자 오버로딩이 되어 있을 것입니다.

 

클래스 iterator로 만든 객체는

자료 구조 안의 데이터를 가리키는 역할로 쓰이죠.

 

그렇기 때문에 * 연산자를 오버로딩하여

사용자가 마치 포인터처럼 사용할 수 있도록 한 것입니다.

 

 

 

강의 출처 : https://www.youtube.com/watch?v=PFc4g8mxOiI&list=PL4SIC1d_ab-aOxWPucn31NHkQvNPHK1D1&pp=iAQB