vector의 메모리 정책

-> vector는 메모리 개수를 초과하는 삽입의 시도가 있을 경우 재할당 및 복사가 발생한다.

-> 재할당은 (기존 메모리 개수 / 2) 만큼 추가로 할당이 된다.

-> 재할당 및 복사를 최소화 하기 위해 사용할 만큼 메모리를 예약하여 사용하는 것이 좋다.

 

#1. 생성자

-> 메모리 개수를 생성자의 인자만큼 만들어준다.

-> 단, 원소도 모두 채워 넣는다.

-> 사용하기 위해서는 clear 이후 push_back을 사용하는 방법과 인덱스 접근을 통한 대입을 이용하면 된다.

1
vector<int> vecInt(5);
cs

 

#2. reserve

-> 객체 생성 후 멤버 함수를 호출하면 된다.

1
2
vector<int> vecInt;
vecInt.reserve(5);
cs

 

비어있는 컨테이너의 begin과 end

1
2
3
4
5
6
7
8
9
10
11
vector<int>        vecInt;
vecInt.reserve(5);
 
vector<int>::iterator        iter_begin = vecInt.begin();
vector<int>::iterator        iter_end = vecInt.end();
 
for (; iter_begin != iter_end; ++iter_begin)
    cout << *iter_begin << endl;
 
if (iter_begin == iter_end)
    cout << "같다" << endl;
cs

위의 결과에서는 메모리 5개가 생성된 상태이지만 원소안에 값이 들어가 있지 않기때문에 begin과 end가 서로 값이 "같다"가 나오게 된다.

'Programming > STL' 카테고리의 다른 글

C++(STL Container) 조건자(algorithm)  (0) 2020.09.28
C++(STL Container) 반복자(iterator)  (0) 2020.09.28
C++(STL Container) vector  (0) 2020.09.27
C++(STL Container) map  (0) 2020.09.27
C++(STL Container) list  (0) 2020.09.27

조건자

-> 알고리즘의 인자로 사용된다.

-> 오름차순 또는 내림차순, 탐색 기준 등 조건을 설정한다.

-> bool타입의 값을 반환하는 함수 포인터, 함수 객체를 사용한다.

 

조건자 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
// 오름차순
template <typename T>
bool Less(T _Dst, T _Src)
{
  return _Dst < _Src;
}
 
// 내림차순
template <typename T>
bool Greater(T _Dst, _Src)
{
  return _Dst > _Src;
}
cs

 

조건자를 통해서 정렬을 시도하려면 알고리즘 함수가 필요하다.

 

알고리즘 함수

-> 알고리즘 함수를 사용하기 위해서는 #include <algorithm> 추가가 필요하다.

 

알고리즘 함수_sort()

1
2
3
4
5
6
7
8
9
10
vector<int> vecInt;
vecInt.push_back(3);
vecInt.push_back(2);
vecInt.push_back(4);
vecInt.push_back(1);
 
sort(beginend, 조건자 함수);
 
sort(vecInt.begin(), vecInt.end(), Less<int>);
sort(vecInt.begin(), vecInt.end(), Greater<int>);
cs

그런데 C++에서는 조건자를 제공하는 _functional 이라는 파일이 존재한다.

-> 단, 함수 객체로 제공해준다.

 

functional 역시 사용을 하기 위해서는 #include <functional> 추가가 필요하다.

1
2
3
4
5
sort(vecInt.begin(), vecInt.end(), less<int>());
sort(vecInt.begin(), vecInt.end(), greater<int>());
 
    for (size_t i = 0; i < vecInt.size(); ++i)
        cout << vecInt[i] << endl;
cs

알고리즘 함수의 sort는 배열 기반 컨테이너만 사용이 가능하다.(노드 기반은 불가능)

-> 배열도 알고리즘 함수의 sort를 사용할 수 있다.

1
2
3
4
int        iArr[5= { 14253 };
 
sort(iArr, iArr + 5, less<int>());
sort(iArr, iArr + 5, Greater<int>);
cs

 

count_if

-> 원소를 순회하면서 조건자에서 true를 반환하는 원소의 개수를 반환한다.

 

count_if를 통해 홀수의 개수를 반환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template <typename T>
bool OddNum(T _num)
{
  if((_num % 2!= 0 )
    return true;
 
  return false;
}
 
void main()
{
  // count_if(begin, end, 조건자 함수);
  int iCnt = count_if(vecInt.begin(), vecInt.end(), OddNum<int>);
 
  cout << iCnt << endl;
}
cs

 

for_each

-> 컨테이너의 원소를 순회하면서 단순 조건자를 수행한다.

-> 조건자의 반환 타입이 bool이 아니어도 상관없다.

-> 대표적으로 컨테이너 원소가 동적할당한 주소를 가질 경우 사용한다.(자주 사용함)

 

일반적인 방식으로 동적할당해제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void main()
{
   vector<int*>  vecPtr;
   vecPtr.push_back(new int);
   vecPtr.push_back(new int);
   vecPtr.push_back(new int);
   vecPtr.push_back(new int);
   vecPtr.push_back(new int);
 
  for(size_t i = 0; i < vecPtr.size(); ++i)
  {
     if(vecPtr[i])
     {
       delete vecPtr[i];
       vecPtr[i] = nullptr;
     }
  }
 
  vecPtr.clear();
 
}
cs

 

for_each()를 통한 동적할당해제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
void Safe_Delete(T& _Dst)
{
  if(_Dst)
  {
    delete _Dst;
    _Dst = nullptr;
  }
}
 
void main()
{
  for_each(vecPtr.begin(), vecPtr.end(), Safe_Delete<int*>);
  vecPtr.clear();
}
cs

동적할당한 주소를 가진 원소를 삭제 하려고 할 때,

동적할당 해제만 하게되면 컨테이너의 메모리는 남아있으므로 할당 해제 후에 clear()를 통해서

메모리도 같이 삭제 시켜줘야 한다.

'Programming > STL' 카테고리의 다른 글

C++(STL Container) vector의 메모리 정책, 생성자, reserve()  (1) 2020.09.28
C++(STL Container) 반복자(iterator)  (0) 2020.09.28
C++(STL Container) vector  (0) 2020.09.27
C++(STL Container) map  (0) 2020.09.27
C++(STL Container) list  (0) 2020.09.27

반복자

-> 포인터와 사용 방법이 동일하지만 포인터가 아닌 단순 객체이다.

-> 연산자 오버로딩을 통해 포인터를 사용 하듯 사용하면 된다.

 

컨테이너마다 원소를 순회하는 방법이 다르다.

-> 하지만 반복자를 이용하면 순회 방법이 획일화 된다.

 

 

반복자 선언

-> 각 컨테이너 내부에 구현되어 있다.

-> 스코프 연산자를 통해서 접근한다.

1
vector<int>::iterator Iter;
cs

 

front와 back

front : vector의 첫 번째 원소에 접근

back : vector의 마지막 원소에 접근

 

반복자의 초기화

-> 컨테이너가 반복자를 반환하게 하면 된다.

 

반복자를 초기화하기 위해 대입을 시도하게 되는데,

여기서 대입 연산자 기준 좌측은 객체이기 때문에

객체 타입을 통해서 초기화를 진행해야 한다.

 

vector.front와 vector.back은 int형 이므로 타입이 달라 불가능하다.

하지만 vector안에 begin()과 end()라는 함수가 존재한다.

 

begin() : 첫 번째 원소의 위치를 가리키는 반복자를 반환

end() : 마지막 원소 다음 위치를 가리키는 반복자를 반환

1
2
vector<int>::iterator Iter_begin = vecInt.begin();
vector<int>::iterator Iter_end = vecInt.end();
cs

 

반복자를 통한 원소 순회

1
2
3
4
for(; Iter_begin != Iter_end; ++Iter_begin)
{
   cout << *Iter_begin << endl;
}
cs

 

반복자의 종류

임의 접근 반복자, 양 방향 접근 반복자, 순 방향 접근 반복자, 입력 반복자, 출력 반복자

 

#1. 임의 접근 반복자

-> 배열 기반 컨테이너들이 가지는 반복자이다.

++, --, [], +=, -=

1
2
3
4
5
6
vector<int>::iterator Iter_begin = vecInt.begin();
 
++Iter_begin;
--Iter_begin;
Iter_begin[4];
Iter_begin+= 4;
cs

#2. 양 방향 접근 반복자

-> 노드 기반 컨테이너들이 가지는 반복자이다.

++, --

1
2
3
4
vector<int>::iterator Iter_begin = vecInt.begin();
 
++Iter_begin;
--Iter_begin;
cs

 

vector의 중간 삽입

insert()

1
2
3
4
5
6
7
8
9
10
11
12
13
vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(3);
vecInt.push_back(4);
 
vector<int>::iterator iter_begin = vecInt.begin();
vector<int>::iterator iter_begin = vecInt.end();
 
iter_begin += 2;
 
vecInt.insert(iter_begin, 999);
vecInt.insert(iter_begin, 9999);
cs

 

중간 삽입 후 확인 방법 두 가지

 

#1. 배열 형식

1
2
3
4
for(size_t i = 0; i < vecInt.size(); ++i)
{
    cout << vecInt[i] << endl;
}
cs

#2. 반복자 형식

1
2
3
4
5
for(; iter_begin != iter_end; ++iter_begin;)
{
   cout << *iter_begin << endl;
}
 
cs

반복자 형식에서 실행을 하면 메모리 누수가 발생한다.

이것을 '반복자의 무효화'라고 한다.

 

반복자의 무효화

원소를 삽입하면 개수가 달라지면서 end의 위치가 변하게 된다.

반복자의 위치가 변하게 될 경우 반복자의 무효화가 발생한다.

 

메모리 개수를 초과하는 삽입의 시도가 있을 경우 재할당 및 복사가 발생한다.

재할당을 하는 순간 begin 또한 위치가 무효화된다.

 

그렇기 때문에 메모리 개수를 초과하는 삽입의 시도가 있을 경우

반복자 초기화를 해줘야 한다.

1
2
3
4
5
6
7
8
iter_begin = vecInt.begin();
iter_end = vecInt.end();
 
for(; iter_begin != iter_end; ++iter_begin)
{
   cout << *iter_begin << endl;
}
 
cs

 

중간 삭제

erase()

 

#1. 일반적인 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(3);
vecInt.push_back(4);
 
vector<int>::iterator iter_begin = vecInt.begin();
vector<int>::iterator iter_end   = vecInt.end();
 
++iter_begin();
++iter_begin();
 
vecInt.erase(iter_begin);
iter_begin = vecInt.begin();
cs

#2. 대입을 통한 중간 삭제

1
2
3
4
5
6
7
8
9
10
11
12
13
vector<int> vecInt;
vecInt.push_back(1);
vecInt.push_back(2);
vecInt.push_back(3);
vecInt.push_back(4);
 
vector<int>::iterator iter_begin = vecInt.begin();
vector<int>::iterator iter_end   = vecInt.end();
 
++iter_begin();
++iter_begin();
 
iter_begin = vecInt.erase(iter_begin);
cs

일반적인 방식으로 중간 삭제를 시도하면 값은 1,2,4가 나오게 되는데,

대입을 통해서 중간 삭제를 하게되면 값이 4만 나오게 된다.

 

이유는 기존에 begin의 위치에 있던 값이 삭제 되었기 때문이다.

begin의 위치에 있던 값이 삭제가 되면 begin은 삭제 된 값의 바로 뒤에 위치하게된다.

만약 일반적인 방식과 같은 값을 출력하고 싶다면,

begin을 다시 초기화 해주면 된다.

1
2
3
iter_begin = vecInt.erase(iter_begin);
 
iter_begin = vecInt.begin();
cs

중간 삭제에서는 반복자 end는 따로 필요없기 때문에

반복자 begin만 초기화를 해줘도 상관없다.

1
2
3
4
5
6
7
8
9
10
11
vector<int>::iterator iter_begin = vecInt.begin();
 
++iter_begin;
++iter_begin;
 
iter_begin = vecInt.erase(iter_begin);
 
for(; iter_begin != vecInt.end(); ++iter_begin)
{
    cout << *iter_begin << endl;
}
cs

 

'Programming > STL' 카테고리의 다른 글

C++(STL Container) vector의 메모리 정책, 생성자, reserve()  (1) 2020.09.28
C++(STL Container) 조건자(algorithm)  (0) 2020.09.28
C++(STL Container) vector  (0) 2020.09.27
C++(STL Container) map  (0) 2020.09.27
C++(STL Container) list  (0) 2020.09.27

vector

-> 배열 기반의 컨테이너이다.

-> 배열 기반이기 때문에 인덱스 접근이 가능하다.(탐색에 용이함)

-> 원소 삽입/삭제 시에는 앞에서부터 할 수 없으며, 맨 뒤에서만 가능하다.

-> 중간 삽입 및 삭제 시에는 삽입 위치의 확보, 삭제 위치의 활용을 위해

-> 해당 원소 이후 포인터의 이동이 발생한다.(선형 시간 O(n))

-> 단, 맨 끝에서 삽입 및 삭제는 포인터 이동이 필요 없다.(상수 시간 O(1))

-> 배열 기반이기 때문에 메모리 개수를 넘어서는 삽입의 시도가 있을 경우

-> 배열의 재할당 및 기존 원소들의 복사가 발생한다.

-> vector의 원소를 삭제하여 원소가 존재하던 메모리 공간은 남아 있는다.

-> 결론적으로 vector는 삽입 삭제가 불리하다고 할 수 있다.

 

vector의 사용법

-> vector를 사용하기 위해서는 #include <vector>를 추가해야한다.

 

vector의 선언

-> 저장하고 관리할 데이터의 자료형을 <>안에 명시해준다.

1
2
vector<int>        vecInt;
vector<float>    vecFloat;
cs

 

원소 삽입

-> push

-> vector는 뒤에서만 삽입이 가능하다.

1
2
3
vector<int>        vecInt;
 
vecInt.push_back(1);
cs

 

원소 삭제

-> pop

1
vecInt.pop_back();
cs

 

size

-> 원소의 개수를 반환하는 함수

1
2
for (size_t i = 0; i < vecInt.size(); ++i)
    cout << vecInt[i] << endl;
cs

 

capacity()

-> 메모리 할당 개수를 반환하는 함수

1
cout << "vecInt.capa: " << vecInt.capacity() << endl;
cs

vector의 메모리 개수를 초과하는 삽입의 시도가 있을 경우 재할당 및 복사가 발생한다.

-> 여기서 재할당은 기존 메모리 개수 / 2 만큼 추가로 재할당이 발생한다.

 

 

clear()

-> 모든 원소를 삭제하는 함수

-> 단, vector에 저장하는 원소가 동적할당된 주소일 경우

-> clear를 호출하기 전에 사용자가 직접 동적할당을 해제해주고 호출해야 한다.

1
vecInt.clear();
cs

 

empty()

-> 원소가 비어있는지 아닌지 검사하는 함수

-> 비어 있을 경우 true, 비어있지 않을 경우 false

1
if (vecInt.empty())
cs

 

swap()

-> swap을 호출하는 컨테이너와 swap의 인자로 넘겨주는 컨테이너의 원소와 메모리 개수를 맞바꾼다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vector<int>     vecInt;
vector<int>     vecTemp;
 
    cout << "vecInt.size: " << vecInt.size() << endl;
    cout << "vecInt.capa: " << vecInt.capacity() << endl;
    cout << "------------------------------------------" << endl;
    cout << "vecTemp.size: " << vecTemp.size() << endl;
    cout << "vecTemp.capa: " << vecTemp.capacity() << endl;
 
    cout << "================swap======================" << endl;
 
    vecInt.swap(vecTemp);
    cout << "vecInt.size: " << vecInt.size() << endl;
    cout << "vecInt.capa: " << vecInt.capacity() << endl;
    cout << "------------------------------------------" << endl;
    cout << "vecTemp.size: " << vecTemp.size() << endl;
    cout << "vecTemp.capa: " << vecTemp.capacity() << endl;
cs

-> swap을 이용하여 메모리 할당 개수 소멸 시키기

1
2
3
4
5
6
7
8
cout << "vecInt.size: " << vecInt.size() << endl;
    cout << "vecInt.capa: " << vecInt.capacity() << endl;
 
    //vecInt.swap(vector<int>());
    vector<int>().swap(vecInt);
 
    cout << "vecInt.size: " << vecInt.size() << endl;
    cout << "vecInt.capa: " << vecInt.capacity() << endl;
cs

 

'Programming > STL' 카테고리의 다른 글

C++(STL Container) 조건자(algorithm)  (0) 2020.09.28
C++(STL Container) 반복자(iterator)  (0) 2020.09.28
C++(STL Container) map  (0) 2020.09.27
C++(STL Container) list  (0) 2020.09.27
C++ STL이란?  (0) 2020.09.27

+ Recent posts