c++
vector 구현.
by kcj3054
2022. 4. 17.
- 먼저 stl이 먼가? -> standard template library이다 여기서 template는 c++의 template이다.
- 그럼 container는 먼가 데이터를 저장하는 객체라고 생각하자. 모든 컨테이너는 iterator를 이용해서 접근이 가능하다. (컨테이너에 상관없이 이터레이터를 사용하면 일관된 방법으로 접근이 가능하다)
간단 구현소스
#include
#include
using namespace std;
//동적배열의 핵심은 이사 횟수를 최소화하는 것이다.
//capacity는 총 집의 크기, size는 내가 사용하는 방의크기
template
class Iterator
{
public:
Iterator() : \_ptr(nullptr)
{
```
}
Iterator& operator++()
{
_ptr++;
return *this;
}
Iterator operator++(int)
{
//원본은 변하지 않고 복사한 값을 전달하고
//원본은 나중에 변한다.
Iterator tmp = *this;
_ptr++;
return tmp;
}
Iterator operator+(const int count)
{
Iterator tmp = *this;
tmp._ptr += count;
return tmp;
}
bool operator==(const Iterator& right)
{
return _ptr == right._ptr;
}
bool operator!=(const Iterator& right)
{
return _ptr != right._ptr;
}
T& operator*()
{
return *_ptr;
}
```
public:
T\* \_ptr;
};
template
class Vector
{
public:
Vector()
{
```
}
~Vector()
{
if (_data)
delete[] _data;
}
void push_back(const T& value)
{
//용량이 꽉찾는지 확인 그렇다면 더큰 공간을 만들어 놓고 더 큰 곳으로 이동
if (_size == _capacity)
{
//증설 작업
int newCapacity = static_cast<int>(_capacity * 1.5);
if (newCapacity == _capacity) newCapacity++;
reserve(newCapacity);
}
//데이터 저장
_data[_size++] = value;
}
//reserve는 capacity 갯수만큼 메모리를 할당한다.
void reserve(int capacity)
{
_capacity = capacity;
T* newData = new T[_capacity];
//데이터 복사
for (int i = 0; i < _size; i++)
newData[i] = _data[i];
if (_data) delete[] _data;
//교체
_data = newData;
}
//복사값이 아니라 &인 이유!
// 출력뿐만 아니라 v[i] = 2 데이터를 넣을 수도 있기때문에
T& operator[](const int pos)
{
//포인터 타입인데 _data[pos]로 접근이 가능하다.
return _data[pos];
}
int size() { return _size; }
int capacity() { return _capacity; }
void clear()
{
//clear함과 동시에 개체의 소멸자도 호출해주어야한다.
if (_data)
{
delete[] _data;
_data = new T[_capacity];
}
_size = 0;
}
```
public:
typedef Iterator iteraotr;
```
iteraotr begin()
{
return iteraotr(&_data[0]);
}
Iterator end()
{
return begin() + _size;
}
```
private:
T\* \_data = nullptr;
int \_size = 0;
int \_capacity = 0;
};
int main()
{
Vector V;
V.reserve(1000); // reserve를 먼저 해놓으면 크기를 미리 만들어놓아서
//계속적인 push\_back으로 인한 유동적인\_capacity는 막을 수 있다.
```
//reserve vs resize
//resize는 데이터 갯수를 조정한다 그래서 capacity도 같이 늘어난다.
/*==============================================================*/
vector<int> v;
v.reserve(10000);
// vector = 동적 배열 = 동적으로 커지는 배열 = 배열
// 원소가 하나의 메모리 블록에 연속해서 저장된다.
/*
* 반환값들이 insert는 삽입한 위치
* erase는 삭제한 위치
*/
vector<int>::iterator insertIt = v.insert(v.begin() + 2, 5);
vector<int>::iterator eraseIt1 = v.erase(v.begin() + 2);
vector<int>::iterator eraseIt2 = v.erase(v.begin() + 2, v.begin() + 4);
//문제가 되는 상황1
//3이라는 데이터가 있으면 일괄 삭제
//iteraotr는 포인터랑 비슷하지만 포인터뿐만아니라 내부적으로 더 들고 있는
// 것이 존재한다. (Myproxy라고 내가 어떤 컨테이너에 소속되어있는지도 보여준다)
//소속 컨테이너도 삭제해주어서 매우 큰일이난다...
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
int data = *it;
if (data == 3)
v.erase(it);
}
//문제 해결 1
for (vector<int>::iterator it = v.begin(); it != v.end();)
{
int data = *it;
if (data == 3)
{
//이렇게하면 값은 삭제하고 해당 위치의 iteraotr를 다시 넣어주니
//Myproxy는 지워지지않는다.
it = v.erase(it);
//else를 하는 이유가 3을 삭제하고 나머지 데이터를 하나씩 이동한 상태라서
//만약 3다음 4가 있다면 it은 4를 가리키는 상태인데 다음루트에서 ++it을 하면
//4는 체크를 안하고 넘어간ㄷ.
}
else
{
++it;
}
}
return 0;