안녕하세요. BlockDMask 입니다.
오늘은 C++ STL의 sequence container 중에 정말 자주 쓰는 vector에 대해서 알아보겠습니다.
<목차>
1) vector container 란?
2) vector의 사용
3) vector의 생성자와 연산자
4-1) vector의 멤버 함수
4-2) vector의 size와 capacity와의 관계 (중요!)
5) vector의 멤버 형식
6) vector를 사용하는 다양한 예제
1) vector container 란?
vector 컨테이너는 자동으로 메모리가 할당되는 배열. 이라고 생각하면 될거같습니다.
저는 C를 하다가 C++로 넘어와서 이렇게 vector 컨테이너를 처음 접하고 정말 소름이 돋았었습니다.
자동으로 메모리를 할당해주고 알아서 끝에 들어가주고 알아서 삭제도 해주고,,,, 정말 효자 컨테이너입니다.
모든 STL 이 그렇듯. template를 사용하기 때문에 데이터 타입은 마음데로 넣을 수 있습니다.
간단하게 그림으로 구조를 먼저 보고 넘어가겠습니다. (약간 자료구조 스택과 비슷한 느낌입니다.)
이러한 구조를 가지고있으며, 맨 뒤쪽에서 삽입과 삭제가 가능합니다.
중간에 값을 삽입 하거나 삭제할 수도 있습니다. 하지만 배열기반이으로 삽입 삭제가 빈번하게 일어난다면 비효율적 입니다.
2) vector 의 사용.
- <vector> 헤더파일을 추가해야합니다.
- using namespace std; 를 해주면 편리합니다.
- vector의 선언은 - vector<[data type]> [변수이름] 입니다.
ex) vector<int> v;
3) vector의 생성자와 연산자. (편의상 int를 사용하겠습니다.)
- vector<int> v;
- 비어있는 vector v를 생성합니다. - vector<int> v(5);
- 기본값(0)으로 초기화 된 5개의 원소를 가지는 vector v를 생성합니다. - vector<int> v(5, 2);
- 2로 초기화된 5개의 원소를 가지는 vector v를 생성합니다. - vector<int> v1(5, 2);
vector<int> v2(v1);
- v2는 v1 vector를 복사해서 생성됩니다.
- vector<int> v1; , vector<int> v2; 가 있고, 내부에 인자들이 있다고 했을때.
연산자 : "==", "!=", "<", ">", "<=", ">=" 로 대소비교 가 가능합니다.
4) vector의 멤버 함수
== vector<int> v; 라고 가정.
== 참조 한다는 것은 해당 데이터를 리턴 한다는 뜻입니다.
- v.assign(5, 2);
- 2의 값으로 5개의 원소 할당. - v.at(idx);
- idx번째 원소를 참조합니다.
- v[idx] 보다 속도는 느리지만, 범위를 점검하므로 안전합니다. - v[idx];
- idx 번째 원소를 참조합니다.
- 범위를 점검하지 않으므로 속도가 v.at(idx)보다 빠릅니다. - v.front();
- 첫번째 원소를 참조합니다. - v.back();
- 마지막 원소를 참조합니다. - v.clear();
- 모든 원소를 제거합니다.
- 원소만 제거하고 메모리는 남아있습니다.
- size만 줄어들고 capacity는 그대로 남아있습니다. - v.push_back(7);
- 마지막 원소 뒤에 원소 7을 삽입합니다. - v.pop_back();
- 마지막 원소를 제거합니다. - v.begin();
- 첫번째 원소를 가리킵니다. (iterator와 사용) - v.end();
- 마지막의 "다음"을 가리킵니다 (iterator와 사용) - v.rbegin();
- reverse begin을 가리킨다 (거꾸로 해서 첫번째 원소를 가리킵니다)
- iterator와 사용. - v.rend();
- reverse end 을 가리킨다 (거꾸로 해서 마지막의 다음을 가리킵니다)
- iterator와 사용. - v.reserve(n);
- n개의 원소를 저장할 위치를 예약합니다(미리 동적할당 해놉니다) - v.resize(n);
- 크기를 n으로 변경한다.
- 더 커졌을 경우 default값인 0으로 초기화 한다.
- v.resize(n,3);
- 크기를 n으로 변경한다.
- 더 커졌을 경우 인자의 값을 3으로 초기화한다.
- v.size();
- 원소의 갯수를 리턴한다. - v.capacity();
- 할당된 공간의 크기를 리턴한다.
- 공간 할당의 기준은 점점 커지면서로 capacity를 할당하게 됩니다.
**size와 capacity에 관계는 4번 항목에서 설명드립니다. 중요하니 꼭 보고 가세요
- v2.swap(v1);
- v1과 v2의 원소와 capacity 바꿔줍니다. (모든걸 스왑해줌)
- v1의 capacity를 없앨때 (할당한 메모리를 프로그램이 끝나기 전에 없애고 싶을때) 사용하기도 합니다.
- v2를 capacity가 0인 임시 객체로 만들어서 스왑을 해줍니다.
- vector<int>().swap(v1); - v.insert(2, 3, 4);
- 2번째 위치에 3개의 4값을 삽입합니다. (뒤엣놈들은 뒤로 밀림) - v.insert(2, 3);
- 2번째 위치에 3의 값을 삽입합니다.
- 삽입한 곳의 iterator를 반환합니다. - v.erase(iter);
- iter 가 가리키는 원소를 제거합니다.
- size만 줄어들고 capacity(할당된 메모리)는 그대로 남습니다.
- erase는 파라미터 하나를 받을때와 두개를 받을 때 다릅니다.
- 그에 따른 예제는 여기있습니다.
- v.empty()
- vector가 비었으면 리턴 true
- 비어있다의 기준은 size가 0이라는 것이지, capacity와는 상관이없습니다.
- v.size();
- 원소의 갯수를 리턴한다. - v.capacity();
- 할당된 공간의 크기를 리턴한다.
- 공간 할당의 기준은 점점 커지면서로 capacity를 할당하게 됩니다.
- dev c++ 기준으로 string 클래스로 vector 를 만들었을때.
원소 갯수 1 => capacity 1
원소 갯수 2 => capacity 2
원소 갯수 3 => capacity 4
원소 갯수 4 => capacity 4
원소 갯수 5 => capacity 8
원소 갯수 6 => capacity 8
원소 갯수 7 => capacity 8
원소 갯수 8 => capacity 8
원소 갯수 9 => capacity 16
을 봐서는2^n으로 capacity의 메모리 할당이 되지 않나싶습니다.(아래에서 테스트 해보겠습니다) - 기존 메모리의 * 2 로 증가하게 됩니다.
- 이런식으로 메모리 할당을 하는 이유는 push_back이 일어날때 마다 동적할당을 하면,
비효율적이므로 미리 정해둔 만큼 동적할당을 한번에 하는 것 입니다. - 원소 개수가 증가하면서, 메모리를 증가해서 따로 할당하게 되면
기존위치에 메모리를 이어서 할당하는게 아니라 새롭게 메모리를 할당해서 원소들을 전부 복사하는 형태인데요.
기존에는 복사에 대한 비용이 많이 들었었습니다. 하지만, std::move 라는 것이 도입되면서 복사하지 않고 이동하게 되어 메모리 증가에 따른 비용이 많이 들지 않게 되었습니다.
**capacity와 size는 다릅니다.
size는 할당된 메모리 안에 요소가 들어있는것의 갯수.
capacity는 할당된 메모리의 갯수? 크기.
이해가 쉽게 되도록 그림을 그려보았습니다.
예시 0) vector size, capacity 에 대한 TEST
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include<iostream> #include<vector> using namespace std; int main(void){ vector<int> v; cout << "[ v[i] , v.size(), v.capacity() ] " << endl; for(int i=0; i<=64; i++){ v.push_back(i+1); cout << "[" << v[i] << " , " << v.size() << " , " << v.capacity() << "]" << endl; } return 0; } | cs |
size는 데이터가 채워진 원소의 갯수 이고, capacity 는 할당된 메모리 공간임을 알 수 있었습니다.
또한, 기존메모리 * 2로 capacity가 증가함을 알 수 있었습니다.
test 환경은, dev c++, win7 x64 이었습니다.
5) vector의 멤버 형식
- iterator - 반복자 형식
- reverse_iterator - 역 반복자 형식
- value_type - 원소의 형식
- size_type - 원소의 개수의 형식
6) vector의 조금 다양한 예시.
예시 1,2,3) 다양한 vector [], at, iterator, size_type 이용한 접근 방법 및 출력 방법
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include<iostream> #include<vector> using namespace std; int main(void){ vector<int> v; v.push_back(21); v.push_back(32); v.push_back(53); v.push_back(64); v.push_back(15); //ex1) 멤버형식 size_type 이용한 반복. cout << "ex1-1) [v.at(i)] size_type : " ; for(vector<int>::size_type i =0; i<v.size(); i++){ cout << v.at(i) << " "; } cout << endl; cout << "ex1-1) [ v[i] ] size_type : " ; for(vector<int>::size_type i =0; i<v.size(); i++){ cout << v[i] << " "; } cout << endl << endl; //ex2) int i 를 이용한 반복. cout << "ex2-1) [v.at(i)] int : " ; for(int i =0; i<v.size() ; i++){ cout << v.at(i) << " "; } cout << endl; cout << "ex2-2) [ v[i] ] int : " ; for(int i =0; i<v.size() ; i++){ cout << v[i] << " "; } cout << endl << endl; //ex3) 반복자 iterator를 이용한 반복. cout << "ex3) [*iter] iterator : "; vector<int>::iterator iter; for(iter = v.begin(); iter != v.end() ; iter++){ cout << *iter << " "; } cout << endl << endl; return 0; } | cs |
>예시 1,2,3의 결과
예시 4, 5, 6) 삽입 삭제 size,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | #include<iostream> #include<vector> #include<string> using namespace std; int main(void){ vector<string> v; v.push_back("Show Me"); v.push_back("Tiger JK"); v.push_back("Dok2"); v.push_back("GAEKO"); v.push_back("ZICO"); //ex4) v.front(), v.back() cout << "//ex4) v.front(), v.back()" << endl; cout << "v.front() : " << v.front() << endl; cout << "v.end() : " << v.back() << endl; cout << endl; //ex5) v.popback() cout << "//ex5) v.popback()" << endl; vector<string>::iterator iter; for(iter = v.begin(); iter != v.end() ; iter++){ cout << *iter << " / " ; } cout << endl; v.pop_back(); for(iter = v.begin(); iter != v.end() ; iter++){ cout << *iter << " / " ; } cout << endl; cout << endl; //ex6) v.erase(iter); cout << "//ex6) v.erase(iter)" << endl; for(iter = v.begin(); iter != v.end() ; iter++){ if(*iter == "Dok2"){ v.erase(iter); break; } } for(iter = v.begin(); iter != v.end() ; iter++){ cout << *iter << " / " ; } cout << endl << endl; //ex7) v.size(), v.capacity(); cout << "//ex7) v.size(), v.capacity()" << endl; cout << "v.size() : " << v.size() << endl; cout << "v.capacity() : " << v.capacity() << endl; return 0; } | cs |
>예제 4, 5, 6 결과
'<개인공부> > [C++]' 카테고리의 다른 글
[C++] multiset container 정리 및 사용법 (0) | 2017.07.27 |
---|---|
[C++] set container 정리 및 사용법 (8) | 2017.07.26 |
[C++] list container 정리 및 사용법 (4) | 2017.07.25 |
[C++] deque container 정리 및 사용법 (2) | 2017.07.23 |
[C++] STL 이란. (0) | 2017.07.19 |
[C++] Pair 클래스 정리 및 예제 (vector, sort) (3) | 2017.07.18 |
[C++] 예외처리 (Exception Handling, try catch) (3) | 2017.07.14 |
[C++] template(템플릿)에 관하여 2 (클래스 템플릿, 템플릿 특수화) (0) | 2017.07.12 |