Publish:

태그: , ,

카테고리:

vector 구현해보자!!

container

종류 설명 ex.
시퀀스 컨테이너 데이터를 선형으로 저장하며,
특별한 제약이나 규칙이 없는 가장 일반적인 컨테이너
vector, deque, list, forward_list
연관 컨테이너 데이터를 일정 규칙에 따라 조직화하여 저장하고 관리하는 컨테이너 set, multiset, map, multimap
컨테이너 어댑터 기존 컨테이너의 인터페이스를 제한하여 만든(기능이 제한되거나 변형된) 컨테이너 stack, queue, priority_queue

vector

생성하면 heap 메모리에 생성되며 동적할당됨.
array에 비해 속도적인 측면에서 떨어지지만 편리하다.
template을 사용하기 때문에 데이터 타입을 마음대로 넣을 수 있다.
내부에 iterator 클래스를 가지고 있기 때문에
vector 의 시작부분을 => .begin() , vector 의 끝 부분을 .end() 로 표현할 수 있다.

목표

template 과 iterator 의 개념을 익히자!

CArr.h

template

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# pragma once
template<typename T>
class CArr
{
private:

public:
  CArr();
  ~CArr();
};

template<typename T>
CArr<T>::CArr()
{
}
  
template<typename T>
CArr<T>::~CArr()
{
}

템플릿 클래스는 모두 헤더파일에서 작성한다.

템플릿 클래스는 클래스가 아니다.

클래스 위에 template<typename T> 와 같이 작성하는데 이를 클래스라고 생각하면 안된다.

클래스를 찍어낼 수 있도록 틀을 만드는 것이다.

만약 .h 파일에 정의하고 .cpp 파일에 구현하게 된다면 Main.cpp 파일에서 오류가 나게 된다.

Main.cpp 가 .h 파일을 코드위 제일 위에서 검사하고 컴파일을 하는데

.cpp 파일의 구현까지 확인할 수 없기 때문이다.

잊지말자. 템플릿은 템플릿일 뿐이다.

변수 추가 및 생성자 수정

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
# pragma once
template<typename T>
class CArr
{
private:
  T* m_pData;
  int m_iCount;
  int m_iMaxCount;
public:
  CArr();
  ~CArr();
};
  
template<typename T>
CArr<T>::CArr()
  : m_pData(nullptr), m_iCount(0), m_iMaxCount(2)
{
  m_pData = new T[2];
}
  
template<typename T>
CArr<T>::~CArr()
{
  delete[] m_pData;
}

이 템플릿은 현재 데이터 개수, 맥스 데이터 개수가 필요하고 T* m_pData 가 필요하다.

왜 포인터(주소값)가 필요할까?

그 이유는 container를 배열로 구성하기 때문이다.

우리가 배열을 만들면 arr[0] 은 그 배열의 시작지점이다.

데이터 묶음의 시작주소를 저장해두는 것이다.

템플릿의 생성자에서 new T[2] 로 size 가 2 인 배열을 생성하고 시작 주소값을 m_pData 에 저장한다.

템플릿의 소멸자에서 delete[] m_pData를 통해서 동적할당된 데이터를 지운다.

동적할당된 데이터가 배열 형식이라면 delete 뒤에 [] 를 붙여주어야 한다.

push_back 함수 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  // 클래스 내부
public:
  CArr();
  ~CArr();
  
  void push_back(const T& _data);
    
  // 클래스 외부
template<typename T>
void CArr<T>::push_back(const T& _data)
{
  if(m_iMaxCount <= m_iCount)
  {
        
  }
  m_pData[m_iCount++] = _data;
}

다음과 같이 push_back 함수를 추가한다.

그리고 Main.cpp 에서 확인해보자.

Main.cpp

1
2
3
4
5
6
7
8
9
10
#include "CArr.h"
#include <iostream>
using namespace std;
int main()
{
    CArr<string> V;
    V.push_back("zero");
    V.push_back("one");
    return 0;
}

테스트를 해보면 데이터 대신 시작 주소값을 넣었기에 들어간 데이터를 눈으로 직접 볼 수는 없지만

다음과 같이 카운트가 증가하는 것을 볼 수 있다.

1

m_iCount 와 m_iMaxCount 가 같아지게 되면 배열이 꽉 찼다는 의미이다.

따라서 다음과 같이 배열을 재할당 해주어야 한다.

1

이 기능을 가진 함수가 Resize() 함수이다.

다음 글에서 push_back 함수 내의 Resize() 함수부터 작성해보자.

방문해 주셔서 감사합니다!😊

업데이트:

댓글남기기