<개인공부>/[C++]

[C++] vector container 정리 및 사용법

BlockDMask 2017. 7. 20. 12:41
반응형

안녕하세요.  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와는 상관이없습니다.
4) vecotr의 size와 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는 다릅니다. 
s
ize는 할당된 메모리 안에 요소가 들어있는것의 갯수.
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


> vector의 size() capacity() 테스트 결과


> 테스트로 확인결과.
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 결과


참고 : http://www.cplusplus.com/reference/vector/vector/

반응형