[ 공 부 ]/[ C + + ]

[ C++ / STL ] Vector 구현해 보기

HiStar__ 2020. 7. 25. 20:31

Vector

 

  • 가장 많이 쓰이는 STL 컨테이너이다.

  • 랜덤 억세스가 가능하다.

 

소 스  코 드

//////////////////////////////////////////////////////////////////////////////////////////
// Kwon O Sung
// Vector 
//////////////////////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <string>
#include <algorithm>
#include <fstream>

typedef __int64 INT;

template<typename T>
class VECTOR {
private:
	T * data;		// 내부 데이터
	INT capacity;	// 총 크기 
	INT size;		// 현재 데이터 사이즈

public:
	// 기본 생성자
	VECTOR(const int n = 1) : capacity{ n }, size{ 0 }, data{ new T[n] } {
	}

	// 소 멸 자
	~VECTOR() {
		if (nullptr != data) delete[] data;
	}

	// 복사 생성자
	VECTOR(const VECTOR& other) {
		if (other.capacity == capacity) {
			size = other.size;
		}
		else {
			if (nullptr != data) delete[] data;
			capacity = other.capacity;
			size = other.size;
			data = new T[capacity];
		}

		std::memcpy(data, other.data, sizeof(T)* size);
	}

	// 이동 생성자
	VECTOR(VECTOR && other) noexcept : capacity{ other.capacity }, size{ other.size }, data{ other.data } {
		other.size = 0;
		other.capacity = 1;
		other.data = new T[other.capacity];
	}

	// 복사 할당 연산자
	VECTOR& operator=(const VECTOR& other) {
		if (this == &other) return *this;
		if (nullptr != data) delete[] data;

		capacity = other.capacity;
		size = other.size;
		data = new T[capacity];

		for (INT i = 0; i < size; ++i) data[i] = other.data[i];
		return *this;
	}

	// 이동 할당 연산자
	VECTOR& operator =(VECTOR &&other) noexcept {
		if (this == &other) return *this;
		if (nullptr != data) delete[] data;
		capacity = other.capacity;
		size = other.size;
		data = other.data;

		other.size = 0;
		other.capacity = 1;
		other.data = new T[other.capacity];
		return *this;
	}

public:
	
	// Emplace_Back : 뒤에 넣기(이동)		
	void Push_Back(const T&);								// Push_Back : 뒤에 넣기(복사)
	// template<typename ... TYPE>
	// void Emplace_Back(TYPE... arg);
	void Clear();											// Clear
	void Reserve(const INT&);								// Reserve : 용량 할당 [ Reserve 한 후에 크기가 증가할 때는 Capacity * ( 2 / 3 ), 내림 ]
	void Resize(const INT&);								// Resize : 용량 할당 후 사이즈 만큼 채운다.
	bool Empty() const;										// Empty : 비어있는지 확인
	INT Size() const;										// Get 크기 함수
	INT Capacity() const;									// Get 용량 함수
	void Swap(VECTOR<T>& other);

	void Sort();											// 오름차순
	void Erase(const INT&, const INT&);						// 인덱스로 범위 지우기
	void Erase(const INT&);									// 인덱스로 하나 지우기


	// 다른 곳에도 사용하는 함수들
	T* begin() const;										// 시작 주소
	T* end() const;											// 끝 주소

	T& front() const;										// 맨 앞
	T& back() const;										// 맨 뒤


	// Operator
	T operator[](const INT&) const;							// 읽기 
	T& operator[] (INT);									// 쓰기
	
	friend std::ostream & operator << (std::ostream&, const VECTOR &); // Ostream : 출력
};

//////////////////////////////////////////////////////////////////////////////////////////
// 메인 문 
int main(int argc, char* argv[]) {
	std::ofstream os;
	
	os.open("Log.txt");
	
	if (os) {
		os << " VECTOR TEST LOG SAVE \n" ;
	}

	VECTOR<int> i1;
	VECTOR<std::string> s1;

	os << " 템플릿을 통한 제네릭한 클래스 생성 확인 [ Push_Back ] \n";

	for (int i = 50; i > 0; --i) i1.Push_Back(i + 1);

	s1.Push_Back(" VECTOR ");
	s1.Push_Back(" TEST ");
	s1.Push_Back(" LOG ");
	s1.Push_Back(" SAVE ");

	os << "\n Int Vector  : ";
	for (const auto& a : i1) os << a << ' ';
	os << "\n String Vector : ";
	for (const auto& a : s1) os << a << ' ';

	os << "\n\n Int Vector 용량 : " << i1.Capacity() << ", " << i1.Size() << '\n';
	os << " String Vector 용량 : " << s1.Capacity() << ", " << s1.Size() << '\n';

	// 오름차순으로 정렬
	s1.Sort();
	i1.Sort();
	os << "\n 오름차순으로 정렬 \n Int Vector  : ";
	for (const auto& a : i1) os << a << ' ';
	os << "\n String Vector : ";
	for (const auto& a : s1) os << a << ' ';

	VECTOR<int> i2;
	VECTOR<std::string> s2;

	i2.Push_Back(3);
	s2.Push_Back(" Hello World !");

	i1.Swap(i2);
	s1.Swap(s2);

	os << "\n\n Swap 함수 \n Int Vector i1 : ";
	for (const auto& a : i1) os << a << ' ';
	os << "\n Int Vector i2 : ";
	for (const auto& a : i2) os << a << ' ';

	os << "\n String Vector s1 : ";
	for (const auto& a : s1) os << a << ' ';
	os << "\n String Vector s2 : ";
	for (const auto& a : s2) os << a << ' ';

	os << "\n Erase 0 ~ 3 : ";
	i2.Erase(0, 3);
	s2.Erase(0, 3);
	os << "\n String Vector i2 : ";
	for (const auto& a : i2) os << a << ' ';
	os << "\n String Vector s2 : ";
	for (const auto& a : s2) os << a << ' ';

	os << "\n Erase 0 : ";
	i2.Erase(0);
	s2.Erase(0);
	os << "\n String Vector i2 : ";
	for (const auto& a : i2) os << a << ' ';
	os << "\n String Vector s2 : ";
	for (const auto& a : s2) os << a << ' ';

	os << "\n\n Int Vector 용량 : " << i2.Capacity() << ", " << i2.Size() << '\n';
	os << " String Vector 용량 : " << s2.Capacity() << ", " << s2.Size() << '\n';

	os.close();

	return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////
// Class
// Push_Back : 뒤에 넣기(복사)
template<typename T>
void VECTOR<T>::Push_Back(const T & other)
{
	if (capacity <= size) {
		T *temp{ nullptr };
		if (9 > capacity) {
			++capacity;
			temp = new T[capacity];
		}
		else { // * (( / 2 ) * 3)
			
			capacity = static_cast<int>((static_cast<float>(capacity) * 1.5f));
			temp = new T[capacity];
		}

		for (INT i = 0; i < size; ++i) temp[i] = data[i];
		// 많은 수가 들어갈 경우 속도를 생각하여 memcpy를 사용하였지만 String 같은 불규칙적인 크기를 가지고 있는 배열을 가지고 있을 경우 
		// 크기에 문제에 따라 잘못된 Heap 접근으로 인하여 Heap에 관련한 오류가 나올 수 있다.
		//std::memcpy(temp, data, sizeof(T)* size);
		temp[size] = other;
		++size;

		if (nullptr != data) delete[] data;
	
		data = temp;
	}
	else {
		data[size] = other;
		++size;
	}
}

template<typename T>
void VECTOR<T>::Clear()
{
	if (nullptr != data) delete[] data;
	capacity = 1;
	size = 0;
	data = new T[capacity];
}

template<typename T>
void VECTOR<T>::Reserve(const INT& num)
{
	if (num <= capacity) return;
	capacity = num;
	T *temp{ new T[capacity] };

	if (size != 0) {
		for (INT i = 0; i < size; ++i) temp[i] = data[i];
		if (nullptr != data) delete[] data;
	}
	
	data = temp;
}

template<typename T>
void VECTOR<T>::Resize(const INT & num)
{
	if (num <= capacity) {
		for (INT i = size; i < num; ++i) data[i] = NULL;
		size = num;
	}
	else {
		Reserve(num);
		for (INT i = size; i < num; ++i) data[i] = NULL;
		size = num;
	}
}



template<typename T>
bool VECTOR<T>::Empty() const
{
	return (size < 1);
}

template<typename T>
void VECTOR<T>::Swap(VECTOR<T>& other)
{
	VECTOR<T> temp(other);

	other = std::move(*this);
	*this = std::move(temp);
}

template<typename T>
void VECTOR<T>::Sort()
{
	std::sort(begin(), end(), [](const T& left, const T& right) {return left < right; });
}

template<typename T>
void VECTOR<T>::Erase(const INT & start, const INT & end)
{
	if (end > size || start < 0) return;

	T *temp = new T[capacity];
	
	INT index{ 0 };
	for (INT i = 0; i < start; ++i) {
		temp[index] = data[i];
		++index;
	}
	for (INT i = end; i < size; ++i) {
		temp[index] = data[i];
		++index;
	}
	size = index;
	
	if (nullptr != data) delete[] data;

	data = temp;
}

template<typename T>
void VECTOR<T>::Erase(const INT & index)
{

	if (index > size || index < 0) return;

	T *temp = new T[capacity];

	INT count{ 0 };
	for (INT i = 0; i < index; ++i) {
		temp[count] = data[i];
		++count;
	}
	for (INT i = index + 1; i < size; ++i) {
		temp[count] = data[i];
		++count;
	}
	size = count;

	if (nullptr != data) delete[] data;

	data = temp;
}


// OPEATOR

// [] Operator : v[1] 
template<typename T>
T VECTOR<T>::operator[](const INT & index)const
{
	if (size < index) exit(1);
	else return *(data + index);
}

template<typename T>
T & VECTOR<T>::operator[](INT index)
{
	return *(data + index);
}

template<typename T>
std::ostream & operator << (std::ostream& os, const VECTOR<T> & rhs)
{
	os << "Capacity : " << rhs.capacity << " | Size : " << rhs.size << '\n';
	for (INT i = 0; i < rhs.size; ++i) os << rhs.size << " ";
	return os;
}

///////////////////////////////////////////////////////////////////////////
// Get 함수들
template<typename T>
INT VECTOR<T>::Size() const
{
	return size;
}

template<typename T>
INT VECTOR<T>::Capacity() const
{
	return capacity;
}


template<typename T>
T * VECTOR<T>::begin() const
{
	return data;
}

template<typename T>
T * VECTOR<T>::end() const
{
	return data + size;
}

template<typename T>
T & VECTOR<T>::front() const
{
	return data[0];
}

template<typename T>
T & VECTOR<T>::back() const
{
	return data[size - 1];
}

 

더 구현 해야할 사항

 

  • emplace_back [ 가변 인자 ]

'[ 공 부 ] > [ C + + ]' 카테고리의 다른 글

[ C++ / STL ] Queue와 Stack  (0) 2020.08.05
[C++] 비트 연산자 사용  (0) 2020.07.10
상속 - 순수 가상 함수  (0) 2019.11.18
Class 상속 Virtual  (0) 2019.11.14
Operator의 사용  (0) 2019.11.13