13. C++ Library 2편 : Container Library가 궁금해

2021. 12. 6. 02:39c++/기초

1. the sequential containers

 

contatiner가 뭘까?

특정 타입의 객체를 담는 공간이다.

 

그렇다면 sequence container는 뭘까?

시퀀스 컨테이너는 데이터를 선형으로 저장하는 일반적인 컨테이너이다.

시퀀스 컨테이너는 삽입된 요소의 순서가 그대로 유지된다.

위는 우리가 흔히 사용하는 시퀀스 컨테이너의 타입이다.

 

시퀀스 컨테이너를 결정하는 법.

 

1. 다른 컨테이너를 사용할 이유가 없다면! vector를 사용해라.

 

2. 너의 프로그램이 작은 element와 space overhead 문제가 많다면 listforward_list사용하지 마라

(space overhead란 어떤 처리를 하는데 쓰이는 메모리를 얘기한다. list의 대표적인 단점은 항목 접근(시퀀셜 액세스)이 오래걸리고, 참조 포인터를 위한 메모리 공간이 낭비된다.)

 

3. 프로그램이 element에 접근할 때 random access를 요구하면 vectordeque를 사용해라.

(vector와 deque는 랜덤 엑세스로 접근하기 때문에! 인덱스 기반의 접근으로 속도가 빠름.)

 

4. 프로그램이 컨테이너 사이에 insert와 delete를 해야한다면 listforward_list를 사용해라.

(연결 list가 insert와 delete가 빠름. )

 

5. 프로그램이 앞과 뒤에서만 insert와 delete를 해야한다면 deque를 사용해라.

 

 

2. Container Library Overview

대다수의 컨테이너는 element type을 제공해주어야 한다.

컨테이너가 사용할 수 있는 유형의 조건

element type이 제공 된 컨테이너를 담는 컨테이너를 정의할 수 있다.

컨테이너는 거의 모든 유형을 저장할 수 있지만 일부 컨테이너의 명령은 element type에 따라 특정 조건이 있을 수 있다.

iterator (반복자) : 모든 element를 순회하며 읽고 수정할 수 있는 타입.

const_iterator : 위 iterator 처럼 동작하지만 수정은 불가능한 타입.

size_type : 컨테이너의 저장할 수 있는 size를 정수형 타입.

이하 생략

 

a.swap(b) :  b와 element를 swap 한다. swap (a,b)와 동일.

c.size() : c의 element의 개수를 return한다. (forward_list에서는 불가능)

c.empty() : c가 element를 가지고 있다면 false를 return한다. 비어 있다면 true.

element를 Add/ Remove하는 명령 (컨테이너의 타입에 따라 명령이 다른 인터페이스도 있다.)

insert(a) : 컨테이너에 특정한 element를 복사해서 넣습니다. 

emplace(a) : 컨테이너에 element에 a를 사용합니다.

erase(a) : 특정 element를 삭제합니다.

clear() element를 전부 삭제합니다.

 

begin() : 첫 element를 가르키는 iterator.

end() : 마지막 요소의 한 칸 뒤의 메모리를 가르키는 iterator이다.

 

이하 생략

 

Iterators (반복자)

반복자의 범위는 begin()(첫 요소)부터 end()(맨 끝 요소)의 다음 메모리까지이다.

 

end()가 맨 끝 요소의 다음메모리를 가르키면(a left-inclusive interval) 좋은 이유.

 

1. begin과 end가 같다면 비어있는 컨테이너이다.

2. begin과 end가 같지 않다면 적어도 element를 하나 가지고 있으며 그러면 begin은 첫번째 element의 레퍼런스가 된다.

3. begin이 end가 같아질 때까지 begin을 증가시킬 수 있다. (모든 요소를 순회 가능)

 

 

 

begin과 end 멤버들

 

const에 대한 포인터 및 참조와 마찬가지로, 우리는 플레인 반복자를 대응하는 const_iterator로 변환할 수 있지만, 그 반대는 아니다. (const_iterator는 값을 변경을 못하니까 아마 상수에 대한 포인터일 듯)

 

컨테이너를 정의하고 초기화하는 법

- 다른 컨테이너를 카피해서 초기화

1. 다른 컨테이너의 직접 카피! (다른 타입의 컨테이너나 element type이 다르면 불가.)

다른 컨테이너를 카피할 때는 위의 예제처럼

첫째 컨테이너의 타입이 match되어야 하고 (list 컨테이너와 deque 컨테이너 not match)

둘째 element의 타입이 맞아야 한다. (string type과 char* type not match)

 

2. 반복자를 사용해 일정 범위의 element를 카피! (array 제외)

 

이 방법을 이용하면 컨테이너의 유형이 동일할 필요가 없다!

그리고 초기화하는 컨테이너의 element로 형변환이 가능하다면 다를 수 있다!

vector와 element의 type이 다르지만 잘 된다! (articles의 처음부터 마지막까지)

반복자로 표시된 부분을 포함하지 않고 복사하는 법. 무슨 말인지 모르겠다.

 

리스트로 초기화해보자!

 

아주 쉽다. 위처럼 그냥 초기화

 

size로 정의된 생성자를 이용해보자!

컨테이너를 정의하고! 동시에 특정한 값으로 초기화하고 싶다면 패러미터로 size와 초기화할 value를 넣어준다.

초기화할 value가 없다면 데이터 타입에 따라 자동으로 value가 설정된다. (int는 0, string은 "")

 

 

array

 

array library를 사용할 때는 아래와 같이 사용한다.

꺽쇠에다 data type과 size를 넣어준다. 하나라도 빠지면 안됨.

 

array는 다른 컨테이너들과 디폴트 생성자로 만들어진 array는 기본적으로 초기화가 되어 있다.

array는 사이즈만큼의 element가 있고 기본적으로 초기화가 되어 있다.

또한 size보다 적게 초기화를 한다면, 나머지는 디폴트값으로 초기화가 된다.

array를 초기화할 때 초기화할 element의 개수는 array의 크기보다 같거나 작아야 한다.

또한 element type이 클래스라면 값 초기화를 하기 위해서 클래스 디폴트 생성자를 가지고 있어야한다.

 

위처럼 기본으로 제공되는 array는 객체를 복사하거나 할당할 수 없지만 array에는 그런 제한이 없다.

다만 크기가 동일해야 한다!

 

값 할당과 swap 

컨테이너 1에 컨테이너 2를 대입 연산자로 넣어줄 경우 c2의 element의 내용이 그대로 복사된다.

두 번째 경우, c1의 element가 초기화가 되고 size의 크기가 조정된다.

array에는 {}를 사용해서 재할당할 수 없다?! 확실하진 않음

swap을 사용할 떄는 매개변수가 되는 두 컨테이너가 꼭 같은 타입이여야 한다. swap은 항상 더욱 빠르다. c2에서 c1으로 element를 복사하는 것보다 항상 속도가 빠르다.

assign() 함수에 iterator 등을 이용하여 값을 할당할 수 있다.

 

<추후 추가 예정>

반응형