본문 바로가기
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;

'c++' 카테고리의 다른 글

라이브러리 개념  (0) 2022.05.16
오버로딩 된 new,  (0) 2022.04.09
참조 vs 포인터  (0) 2022.01.02
cpp transform  (0) 2021.12.15
static 키워드 (cpp, java)  (0) 2021.10.23