STL 컨테이너는 시퀀스 컨테이너와 연관 컨테이너로 나눌 수 있다. 

시퀀스 컨테이너가 저장 원소가 삽입 순서에 따라 상대적인 위치(순서)를 갖는 컨테이너이며, 연관 컨테이너는 특정 정렬 규칙에 따라 저장 원소가 정렬되는 컨테이너이다. 


* 시퀀스 컨테이너

vector 컨테이너는 대표적인 시퀀스 컨테이너로 배열과 비슷하여 사용이 쉽다. 그리고 자주 사용된다. 

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
#include<iostream>
#include<vector>
#include <algorithm>
#include<list>
#include<stack>
using namespace std;
 
int main()
{
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
 
    for (vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] << endl;
    
    cout << typeid(vector<int>::size_type).name() << endl;  
    //vector<int>::size_type: vector의 크기, 첨자 형식을 위한 typedef 멤버 형식이다. 
 
 
    return 0;
 
 
}
 
cs


* 참조

참조는 값을 복사하지 않고 같은 메모리 공간의 이름(참조) 이다. 


*capacity() 

vector만 가지는 멤버 변수이다. 메모리 재할당 문제를 해결하고 성능 문제를 보안시켰다. 

즉, 미리 넉넉한 메모리를 확보하면 재할당과 이전 원소를 복사하는데 드는 비용을 줄일 수 있다.

메모리 예약 함수 reverse() 메모리 예약 함수를 제공한다. 

reverse()를 사용하면 미리 메모리를 할당해 capacity를 결정하고 vector에 원소가 추가되더라도 메모리를 재할당 하지 않는다. 



*vector의 주요 특징 정리

vector는 임의 접근 반복자를 지원하는 배열 기반 컨테이너이다. vector의 가장 큰 특징중 하나는 원소가 하나의 메모리 블록에 연속(배열 기반 컨테이너)하게 저장된다는 것이다. 그러다 보니, 원소가 추가되거나 삽입될때 메모리 재할당이 발생할 수 있고 상당한 비용을 지불하게 된다. 

또한 벡터는 시퀀스 기반 컨테이너이다. 시퀀스 기반 컨테이너는 원소가 서로 상대적인 위치(순서)를 유지하므로 가장 앞 요소와 가장 뒤 요소를 참조하는 front(), back(0 멤버함수를 제공하여 컨테이너 끝에 추가하고 제거하는 push_back(), pop_back() 멤버 함수를 제공한다. 하지만, vecotr에는 배열기반 컨테이너이므로 push_front()와 pop_front() 멤버 함수는 제공하지 않는다. 이 두함수는 vector에 매우 비 효율적으로 작동한다. 


*deque의 주요 특징 정리

deque는 시퀀스 컨테이너 이며 배열 기반 컨테이너이다. vector와 유사하다. vector와 다른점은 원소가 메모리 블록에 연속하게 저장되지만 하나의 메모리블록이 아닌 여러 메모리 블록에 나뉘어 저장된다는 것이다.

vector는 모든 원소를 뒤쪽으로만 밀어낼 수 있지만, deque는 뒤쪽이나 앞쪽으로 밀어낼 수 있다. 

at() 과 [] 연산자를 지원한다. 


*list 컨테이너

list 컨테이너는 vector와 deque처럼 시퀀스 컨테이너로 원소가 상대적인 순서를 유지한다. list 는 노드 기반 컨테이너로 원소가 노드 단위로 저장되며 list는 이중 연결 리스트로 구현된다. 


*list의 주요 특징 정리

list는 시퀀스 컨테이너이며 노드 기반 컨테이너 이다. 그래서 순차열 중간에 삽입, 제거가 빈번하게 발생하며 원소의 상대적인 순서가 중요하다면 list 컨테이너를 사용한다. list는 이중 연결 리스트 구조로 원소를 앞, 뒤 에 모두 추가할수있는 push_front(), pop_front() ... 멤버함수를 제공한다.

또한, 시퀀스 컨테이너이므로 가장 첫 원소와 마지막 원소의 참조를 반환하는 front()와 back()멤버함수를 제공한다. 

단, 노드 기반 컨테이너 이므로 [] 연산자나 at() 멤버함수는 제공하지 않는다. 


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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include<iostream>
#include<vector>
#include <algorithm>
#include<list>
#include<stack>
using namespace std;
 
int main()
{
 
    /*
    vector의 capacity()
    vector<int> v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(50);
    for (vector<int>::size_type i = 0; i < v.size(); ++i)
        cout << v[i] << endl;
    
    cout << typeid(vector<int>::size_type).name() << endl;  
    //vector<int>::size_type: vector의 크기, 첨자 형식을 위한 typedef 멤버 형식이다. 
    cout << v.size() << endl; //저장 원소 개수 
    cout << v.capacity() << endl; //실제 할당된 메모리 공간의 크기
    cout << v.max_size() << endl; //컨테이가 담을 수 있는최대 원소의 개수
    */
    /*
    vector의 reserve()
    vector<int> v;
    v.reserve(8);
    cout << "size : " << v.size() << " capacity :" << v.capacity() << endl;
    v.push_back(10);
    cout << "size : " << v.size() << " capacity :" << v.capacity() << endl;
    v.push_back(20);
    cout << "size : " << v.size() << " capacity :" << v.capacity() << endl;
    v.push_back(30);
    cout << "size : " << v.size() << " capacity :" << v.capacity() << endl;
    v.push_back(40);
    cout << "size : " << v.size() << " capacity :" << v.capacity() << endl;
    v.push_back(50);
    cout << "size : " << v.size() << " capacity :" << v.capacity() << endl;
    v.push_back(60);
    cout << "size : " << v.size() << " capacity :" << v.capacity() << endl;
    v.push_back(70);
    cout << "size : " << v.size() << " capacity :" << v.capacity() << endl;
    v.push_back(80);
    cout << "size : " << v.size() << " capacity :" << v.capacity() << endl;
    v.push_back(90);
    */
 
    /*vector의 생성자
    vector<int> v1(5); //0으로 초기화된 size가 5인 컨테이너
     v1.push_back(10);
    v1.push_back(20);
    v1.push_back(30);
    v1.push_back(40);
    v1.push_back(50); 
    for (vector<int>::size_type i = 0; i < v1.size(); ++i)
        cout << v1[i] << "";
    cout << endl;
    vector<int> v2(5); //0으로 초기화된 size가 5인 컨테이너
    v2[0] = 10;
    v2[1] = 20;
    v2[2] = 30;
    v2[3] = 40;
    v2[4] = 50;
    //0에서 10,20,30,40,50 으로 수정했다.
    for (vector<int>::size_type i = 0; i < v2.size(); ++i)
        cout << v2[i] << " ";
    
    vector<int> v3(5,10)
    for(vector<int>::size_type i=0; i<v3.size(); ++i)
        cout<<v3[i]<< ""; //10으로 초기화됨
    v3.resize(10); //기본값 10으로 초기화된 size가 10인 컨테이너로 확장된다.
    for(vector<int>::size_type i = 0; i<v.size(); ++i)
        cout<<v[i]<<"";
    cout<<endl;
    cout<<"size :"<<v.size()<<" capacity :"<<v.capacity()<<endl; //capacity는 10으로 확장됨
    v.resize(5); //capacity는 변함이 없음
    for(vector<int>::size_type i =0; i<v.size(); ++i)
        cout<<v[i]<<"";
    cout<<endl;
    cout<<"size : "<<v.size()<<" capacity:"<<v.capacity()<<endl;
    v3. clear(); // 비운다. clear() 해도 capacity는 여전히 사라지지 않는다. 남아있게 된다. 
    if(v3. empty())
    {
        cout<<"v3에 원소가 없습니다."<<endl;
    }
    vector<int>().swap(v3); //기본 생성자로 만든 vector 컨테이너와 v3 컨테이너를 swap 한다. capacity는 0이 된다. 
    vector<int> v4;
    v4.push_back(10);
    v4.push_back(20);
    v4.push_back(30);
    v4.push_back(40);
    v4.push_back(50); 
    
    v4.front() = 100; //첫번째 원소를 100으로
    v4.back() = 500; //마지막 원소를 500으로 
    for(vector<int>::size_type i=0; i< v.size(); ++i)
        cout<<v[i]<<endl;
    //시퀀스 컨테이너 중 배열 기반 컨테이너인 vector와 deque는 일반 배열처럼 임의 위치의 원소를 참조하는 두 인터페이스를 제공한다.
    // [ ]연산자와 at() 멤버 함수이다. 
    //두 인터페이스의 기능은 같지만 [ ] 연산자는 범위 점검을 하지 않아 속도가 빠르며 at() 멤버함수는 범위를 점검하므로 속도가 느리다.
    
    v4.at(0) = 1000; //범위 점검 있는 0 index 원소의 참조
    v4.at(4) = 5000; //범위 점검 있는 4 index 원소의 참조 
    //결과적으로 [] 연산자와 at() 멤버함수의 기능이나 결과는 같다.
    try
    {
            cout<<v4.at(0)<<endl;
            cout<<v4.at(3)<<endl;
            cout<<v4.at(6)<<endl; //throw out_of_range 예외
    }
    catch(out_of_range &e)
    {
            cout<<e.what()<<endl;
    } //왜? 범위를 체크하기 때문이다.
    //v.assign(5,2); // 5개의 원소값을 2로 할당
    //begin()과 end() 멤버 함수를 사용한 간단한 예제. 위와 차이가 있다.
    for(vector<int> :: iterator iter = v4.begin(); iter!=v4.end(); ++iter)
        cout<<*iter<<"";
    //반복자를 사용할 경우에는 다음을 선언한다.
    vector<int> :: iterator iter = v.begin();
    iter += 2 ; // +2 한 위치의 원소(30)을 가리킨다. 
    //상수 반복자를 사용하면 const 포인터처럼 데이터를 읽기 전용으로 안전하게 사용할 수 있다. 
    vector<int>::const_iterator citer = v4.begin();
    cout<<*citer<<endl; //가리키는 원소의 상수 참조 , 주의 해야 할것은 동작하여 반복자를 이동할 수 없으므로 사용에 주의해야 한다.
    vector<int>::iterator iter2;
    iter2 = v.insert(iter, 100); //iter에는 값이 있다. 10,20,30,40,50 가정, 그래서 iter를 삽입하게 되면 한칸 밀리게 된다.
    
    v.insert(iter, 3, 100); //iter가 가리키는 위치에 정수 100을 3개 삽입
    v2.insert(iter, v.begin(), v.end()); //iter가 가리키는 위치에 [v.begin(), v.end()) 구간의 원소를 삽입한다. 
    //원래 10,20,30,40,50 의 수가 있다고 치면 10 20 100 100 100 30 40 50 이고 
    //100 10 20 100 100 100 30 40 50 200 300 으로 된다. 
    //특정 위치의 원소를 제거하려면 erase 멤버 함수를 사용한다. erase는 반복자를 사용하여 원소를 한개 혹은 여러개 제거할 수 있다.
    cout << endl;
    return 0;
    
    */
 
 
    
    return 0;
 
 
 
 
}
 
cs


'C++ STL' 카테고리의 다른 글

C++STL11 :: map<key,value>  (0) 2020.09.23
C++STL10 :: adjacent_find()  (0) 2019.01.05
C++ STL09 :: 연관 컨테이너  (0) 2018.12.30
C++STL07 :: STL 소개(2)  (0) 2018.12.30