생성자와 소멸자 코드

	MyVector()
	{
		//my_base가 nullptr지만
		//사이즈및 캐퍼시티가 0이므로 원소를 추가할때 Reserve()함수에서 할당이 이뤄집니다
		this->my_base = nullptr;
		this->my_capacity = this->my_size = 0;
	}
	MyVector(std::initializer_list<Data> list)
	{
		this->my_capacity = this->my_size = 0;
		this->Reserve(list.size());

		for (auto& element : list)
		{
			this->my_base[this->my_size++] = element;
		}
	}
    //MyVector<int> my_vector({ 1, 2, 3, 4 });
	~MyVector()
	{
		if (this->my_base)
		{
			delete[] this->my_base;
		}
	}

벡터를 생성할 때 즉시 원소를 넣고싶으면 2번째 생성자처럼

MyVector<int> my_vector({ 1, 2, 3, 4 });

이렇게 넣으면된다. 

 

소멸자가 호출되면 벡터 내부에 포인터로 작성된 배열을 해제하는것을 볼 수 있다.

 

 

캐퍼시티(Capacity)란?

캐퍼시티: 배열의 빈공간을 포함한 최대크기.

사이즈: 배열의 원소갯수.

 

std::vector는 원소를 추가할 때 사이즈가 캐퍼시티를 초과하면 새롭게 캐퍼시티를 할당합니다.

 

그냥 배열에 추가하면 알아서 되는거아냐?

새롭게 캐퍼시티를 할당하는게 왜?

어쨌든 잘 돌아가면 되는거 아냐?

 

라고 생각하면 당신은 주니어(라고 포프님이 그랬습니다)

 

캐퍼시티의 할당을 고려하지 않고 배열을 생성하게 되면 퍼포먼스의 악영향을 끼칠 수 있습니다.

단순히 10개 100개 1000개를 만드는건 크게 체감되지 않을테지만, 특정한 상황에선 고려해야합니다.

왜그럴까요? 우선 코드부터 봅시다

template <typename Data>
class Container_Master
{
protected:
	Data* my_base = nullptr;
	size_t my_capacity = 0;
	size_t my_size = 0;

	//캐퍼시티를 늘릴 때 지정된 값이 없다면 해당 값만큼 늘립니다
	const size_t additive_capacity = 32;
public:
	//컨테이너의 공간을 새로 생성합니다
	void Reserve(size_t capacity)
	{
		//기존 캐퍼시티가 더 크다면 재할당을 하지 않습니다
		if (my_capacity >= capacity)
			return;

		Data* temp = new Data[capacity];
		my_capacity = capacity;

		//컨테이너에 원소가 있다면 새로 할당한 주소로 옮겨줍니다
		if (my_size >= 1)
		{
			for (size_t i = 0; i < my_size; i++)
			{
				temp[i] = my_base[i];
			}
			delete[] my_base;

		}

		my_base = temp;
	}
};

Reserve()함수 입니다.

 

간단하게 문장으로 표현하면 이렇습니다

1. new를 사용해 새롭게 할당.

2. for루프로 기존 원소를 새롭게 할당한 곳에 전부 이동.

3. 기존에 할당된 배열(Data*)은 삭제하고 새롭게 할당된 배열을 등록합니다

 

이미지로 보자면...

기존 배열의 원소가 하나씩 이동하는것을 볼 수 있다.

첫번째 이미지 처럼 원소를 가진상태로 배열의 사이즈가 꽉차서 재할당이 이뤄지면 모든 원소가 새로운 배열로 이동하는것을 볼 수 있다. 이미지는 7개밖에 되지 않지만

만약 원소가 만개라면? 십만개라면?

게다가 재할당할때 마다 캐퍼티시는 여러개가 추가되는게 아니라 std::vector를 기준으로 1개만 추가된다.

그러면 만개의 원소를 하나 추가한다고 가정하면 1+2+3+4+5+...+9999 만큼 원소가 이동하게 되고 10000번의 재할당이 이뤄진다. 메모리 파편화의 가능성도 있다.

언리얼엔진같은 경우는 더 많이 캐퍼시티가 증가하지만 그것이 근본적인 해결책이 되진 않는다.

 

그렇기에 배열(벡터)을 생성하게 된다면 꼭 미리 할당을 해야한다.

원소를 10개 채울려면 원소를 추가하기 전에 Reserve(10)함수를 사용하면된다.

만약 원소를 몇개 채울지 모르겠다면 추정치라도 Reserve()해준다.

 


std::vector는 예기치 않게 캐퍼시티를 늘릴 경우 1만 늘어나는것을 나는 32개의 캐퍼시티를 늘리게 구현해놨다.

처음엔 기존원소개수의 2배씩 캐퍼시티를 늘릴까 생각했지만, 그렇게까지 할 필요를 못느껴서 32개로 고정했다.

32개로 설정한 이유는... 없다. 그냥 느낌이 32개가 좋다. 뭔가 적절한느낌 이다.

 

 

 

https://github.com/ForestBird1/MyContainer

 

GitHub - ForestBird1/MyContainer

Contribute to ForestBird1/MyContainer development by creating an account on GitHub.

github.com

 

+ Recent posts