강의 보고 공부한 것을 정리하는 목적으로 작성된 글이므로 틀린 점이 있을 수 있음에 양해 부탁드립니다. (피드백 환영입니다)
사실 vector
만 본다면 저번에 공부했던것만 알고 있는다면 대략적으로 사용이 가능하다.
하지만 iterator
에 대하여 더 궁금해 할 수 있다.
도대체 어떤 원리로 작동 하는 것인가?
그래서 우리가 예전에 만들었던 vector를 가지고 와서 여기서 iterator를 구현을 해보겠다!
먼저 예전에 구현했던 vector코드이다. 여기서 하나하나 추가할 것이다.
#pragma once
#include <assert.h>
template<typename T>
class Vector
{
public:
explicit Vector()
{
}
~Vector()
{
if (_buffer)
delete[] _buffer;
}
void clear()
{
// TODO
if (_buffer)
{
delete[] _buffer;
_buffer = new T[_capacity];
}
_size = 0;
}
void push_back(const T& data)
{
// TODO
if (_size == _capacity)
{
// 증설 작업
int newCapacity = static_cast<int>(_capacity * 1.5);
if (newCapacity == _capacity)
newCapacity++;
reserve(newCapacity);
}
// 데이터 저장
_buffer[_size] = data;
// 데이터 개수 증가
_size++;
}
void pop_back()
{
// TODO : 소멸
_size--;
}
T& back()
{
return _buffer[_size - 1];
}
void resize(int size)
{
// TODO
reserve(size);
_size = size;
}
void reserve(int capacity)
{
if (_capacity >= capacity)
return;
_capacity = capacity;
T* newData = new T[_capacity];
// 데이터 복사
for (int i = 0; i < _size; i++)
newData[i] = _buffer[i];
if (_buffer)
delete[] _buffer;
_buffer = newData;
}
T& operator[](int index)
{
assert(index >= 0 && index < _size);
return _buffer[index];
}
int size() { return _size; }
int capacity() { return _capacity; }
private:
T* _buffer = nullptr;
int _size = 0;
int _capacity = 0;
};
일단 iterator
는 클래스안에 있는 클래스이기 때문에 vector class안에 만들어 주면 된다.
하지만 보기가 힘들어서 빼서 만든다면 이런식으로도 만들 수 있다.
class Iterator
{
};
class Vector
{
public:
using iteraotr = Iterator<T>;
}
이런식으로 맵핑을 해줄 수 있다.
그러면
Vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
Vector<int>::iterator it;
이런식으로 사용해줄 수 있다.
즉, iterator
는 하나의 클래스에 불과하고 그 클래스가 vector에 소속되어 있는 느낌이다.
그럼 우리는 이 iterator를 통하여
list
냐 vector
에 따라 세부적으로는 다르겠지만 전체적인 인터페이스에서는 바뀌는 것이 별로 없기 때문에 구현을 해보겠다.template<typename T>
class Iterator
{
public:
Iterator() : _ptr(nullptr) { }
Iterator(T* ptr) : _ptr(ptr) { }
// 전위형 ++it
Iterator& operator++()
{
_ptr++;
return *this;
}
// 후위형 it++
Iterator operator++(int)
{
Iterator temp = *this;
_ptr++;
return temp;
}
Iterator operator+(const int count)
{
Iterator temp = *this;
temp._ptr += count;
return temp;
}
bool operator==(const Iterator& other)
{
return _ptr == other._ptr;
}
bool operator!=(const Iterator& other)
{
return _ptr != other._ptr;
}
T& operator*()
{
return *_ptr;
}
public:
T* _ptr = nullptr;
}
이런식으로 인터페이스를 맞춰주면 된다.
그리고 우리는 vector클래스 안에서 begin이랑 end를 구현해주면 된다.
iterator begin() { return iterator(&_buffer[0]); }
iterator end() { return begin() + _size; }
이런식으로 만들어주면 된다.
그럼 사용을 해본다면
Vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
Vector<int>::iterator it;
for(it = v.begin(); it != v.end(); it++)
{
int data = *it;
cout << data << endl;
}
이런식으로 잘 실행이 된다는 것을 알 수 있다.
대부분의 사람들은 iterator를 신비한 존재? 이런식으로 생각을 하는 사람들이 많은데 직접 구현을 해본다면 단순하게 인터페이스를 맞춰서 구현만 하면 끝나는 부분이라고 볼 수 있다.
어떻게 보면 iterator
는 AddOn느낌이라고 볼 수 있다.
실제 vector
는 잘 구현되어 있지만 그 vector
를 대상으로 반복자라고 해서 첫 번째 데이터부터 다음다음다음 데이터까지 넘어갈 수 있는 수단을 맵핑을 해주는 것이라고 볼 수 있다. 소위말해서 Wrapper class라고 한다.
어떤 기능을 다시한번 포장을 해서 제공하는 느낌이라고 보면 된다.
앞으로 iterator
가 등장해도 겁먹고 대단하다 생각하지말자.
이제 이정도면 vector
에 대해서 어느정도는 공부를 한 것 같다.
앞으로 list
, map
, hash map
정도만 한다면 개발의 필요한 container는 졸업했다고 보면된다.
그래서 기본기들만 잘 이해하기만 해도 중간을 갈 수 있다!
위에서 이야기한 size capacity와 중간삽입삭제 이런 기초적인 것들만 잘 머리속에 넣어놓기만 하면 우리는 중간은 갈 수 있다.
너무 코딩 면접이나 시험에 겁먹을 필요는 없다.
어차피 실무를 간다고 하더라도 다들 비슷하게 사용한다.
지금 우리가 배우고 있는 것이 정수만 저장하면서 공부를 하다보니까 하찮게 여길 수도 있다.
하지만 나중에 우리가 저기에 몬스터, 아이템, 퀘스트 등 게임에 적용이 되기 시작한다면 그것이 컨텐츠라고 볼 수 있다.
그래서 앞으로 조금만 더 배우면 프로그래밍적으로는 대부분은 알 수 있게 될 것이고
지금까지 배워던 것들을 활용하여서 컨텐츠를 만들면 되는 것이다.
물론 vector
든 list
든 처음에는 익숙하지 않겠지만 점점 사용을 하다보면은 익숙해 질 것이다.
겁먹지말고 계속 앞으로 나아가자!
다음에는 list
를 공부해 볼 것이다.