1. vector 구현하기

vector를 클래스로 구현하는 연습을 한다.

 

(1) Vector 클래스 구성하기

#include <iostream>
#include <vector>
using namespace std;

template<typename T>
class Vector
{
public:
    Vector() : _data(nullptr), _size(0), _capacity(0)
    {

    }

    ~Vector()
    {
        if (_data) // 데이터가 있으면 true 반환
            delete[] _data; // 객체 삭제, 배열의 형태이므로 delete[]
    }

    int size() {return _size;} // size 값을 반환하는 명령어
    int capacity() {return _capacity;} // capacity 값을 반환하는 명령어

private:
    T* _data;	// 포인터
    int _size;
    int _capacity;
};

기본 생성자에서 멤버 변수를 초기화해준다.

소멸 생성자에서 데이터 영역을 지워주도록 한다. 이 때 배열이므로 문법에 주의하여야 한다.

 

(2) push_back 구현

동적 배열의 끝에 값을 추가하는 push_back 함수를 구현한다.

    void push_back(cosnt T& val)
    {
        if (_size == _capacity) // 메모리 증설 조건
        {
            int newCapacity = static_cast<int>(_capacity * 1.5); // 정수에 실수를 곱하면 짤림
            if (newCapacity == _capacity)
                newCapacity++;  // 1에 1.5를 곱해도 1이므로, 같으면 1을 늘리게 설정
        
            reserve(newCapacity) // 캐퍼시티 증설 완료
        }
    }

위 코드는 사이즈(정수)와 커패시티(정수)를 비교하여 같으면 새로운 커패시티를 이전 커패시티의 1.5배로 증설하게 만든다. 이 때 정수 1에 1.5를 곱해도 1이 되므로 2가 되게 하기위하여 새로운 커패시티에 1을 더해주도록 작성한다.

 

다음으로 배열의 끝에 원소를 추가하도록 코드를 작성한다.

    void push_back(const T& val)
    {
        if (_size == _capacity) // 메모리 증설
        {
            int newCapacity = static_cast<int>(_capacity * 1.5); // 정수에 실수를 곱하면 짤림
            if (newCapacity == _capacity)
                newCapacity++;  // 1에 1.5를 곱해도 1이므로, 같으면 1을 늘리게 설정
        
            reserve(newCapacity); // 캐퍼시티 증설 완료
        }
        _data[_size] = val; // 사이즈 만큼의 원소로 이동 후에 값을 집어넣음
        _size++; // 사이즈를 증가시킴(값이 추가되었기 때문에)
    }

사이즈 만큼 접근해서 끝에 값을 집어넣는다.

 

(3) reserve 구현

동적 배열의 capacity를 늘리는 reserve 함수를 구현한다.

    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;

    }

기존의 capacity의 작동 방법 처럼 구현한다.

(사이즈가 커패시티만큼 커지면 1.5배 확장하여 메모리를 증설하고, 증설한 메모리로 모든 값을 복사/이동 시킴)

 

(4) 배열 임의 접근을 위한 배열 인덱스 연산자 오버로딩

V.[1] = 1 같은 코드를 작동할 수 있도록 배열 인덱스 연산자인 '[ ]'를 오버로딩하도록 한다.

   T& operator [] (const int pos) { return _data[pos]; } // 실제 값을 변경하기 때문에 참조타입을 사용

 

2. 반복자(Iterator) 구현

반복자를 증감해야 함.

역 참조를 통해 데이터에 접근할 수 있게 해야함.

template<typename T>
class Iterator
{
public:
    Iterator() : _ptr(nullptr)
    {

    }

    Iterator(T* ptr) : _ptr(ptr)
    {

    }

	~Iterator() {};

public:
    T* _ptr; // 데이터의 포인터를 가리킴.
    // Myproxy 구현은 생략함.
};

 

(1) 증감 연산자 오버로딩

    // it++, ++it, 각종 증감 연산자 오버로딩
    Iterator& operator++() // 전위형 -> 참조 형태로 만듬, ++(++it)가 가능하도록
    {
        _ptr++;
        return *this; // 자기 자신의 주소를 리턴
    }

    Iterator operator++(int) // 후위형
    {
        Iterator temp == *this;
        _ptr++;
        return temp;
    }

    Iterator& operator--() // 전위형 -> 참조 형태로 만듬, ++(++it)가 가능하도록
    {
        _ptr--;
        return *this; // 자기 자신의 주소를 리턴
    }

    Iterator operator--(int) // 후위형
    {
        Iterator temp == *this;
        _ptr--;
        return temp;
    }

 

(2) 비교 연산자 오버로딩

    // 비교 연산자 오버로딩
    bool operator==(const Iterator& right)
    {
        return _ptr == right._ptr; // 기존의 _ptr이 우변의 _ptr과 같은지
    }

    bool operator!=(const Iterator& right)
    {
        return _ptr != right._ptr; // 기존의 _ptr이 우변의 _ptr과 다른지
    }

또는 != 연산자를 만들 때 지금 포인터가 우변과 같은지 판별한 후 한번 뒤집어 줄 수 있다.

return !(*this == right)

 

(3) 포인터 연산자 ' * ' 오버로딩

    T& operator*()
    {
        return *_ptr; // *를 붙이면 실제 데이터를 건내주게 함
    }

 

3. 반복자를 사용하는 vector의 문법들 구현

다시 Vector 클래스로 돌아가서 작성한다.

public:
    typedef Iterator<T> iterator;

    iterator begin() { return iterator(&_data[0]);}
    iterator end() { return begin() + _size();}

한편, 반복자에서 덧셈 연산에 대하여 오버로딩 하지 않았으므로 그 부분을 구현해준다.

 

(1) 반복자의 덧셈, 뺄셈 연산자 오버로딩

    Iterator operator+(const int count) // count 만큼 이동
    {
        Iterator temp = *this;
        temp._ptr += count;
        return temp;
    }

    Iterator operator-(const int count) // count 만큼 이동
    {
        Iterator temp = *this;
        temp._ptr -= count;
        return temp;
    }

 

(2) clear 문법 구현

    void clear() { _size = 0; }

캐퍼시터는 유지하고 사이즈만 초기화한다.

'기초 C++ 스터디 > 예제' 카테고리의 다른 글

9-9. STL 실습  (0) 2023.06.19
9-5. STL - List 구현하기(실습)  (0) 2023.06.14
7-3. 디버깅 예제 #8 ~ 10  (0) 2023.06.07
7-2. 디버깅 예제 #5 ~ 7  (0) 2023.06.07
7-1. 디버깅 예제 #1 ~ 4  (0) 2023.06.07