Allocator

강보석·2024년 3월 19일

이번에는 Allocator에 대해 얘기해볼 것입니다. 말 그대로 할당자라는 뜻으로 동적 할당에 관련해서 볼 것입니다.
우리는 주로 new Knight() 등을 통해 동적할당을 합니다.
여기서 new는 Knight 클래스만큼의 용량을 할당을 해주고 생성자 또한 알아서 실행시켜줍니다.
이것만으로도 충분히 좋은 명령어이지만 하다보면 뭔가 추가옵션을 넣어주고 싶을 수 있습니다. 이를 통해 버그가 일어날 수 있는 부분을 보완하거나 메모리 단편화 문제를 해결할 수 있을 것입니다.

이번 포스팅에는 어떤 식으로 추가옵션을 줄 수 있는지에 대해 써볼 것입니다.

new, delete에 추가 명령어 넣기

void* operator new(size_t size) {
	cout << "new!" << endl;
	void* ptr = malloc(size);
	return ptr;
}

void operator delete(void* ptr) {
	cout << "delete!" << endl;
	free(ptr);
}

class Knight {
public:
	Knight() {
		cout << "Knight()" << endl;
	}
	Knight(int32 hp) : _hp(hp) {
		cout << "Knight(hp)" << endl;
	}
	~Knight() {
		cout << "~Knight()" << endl;
	}

public:
	int32 _hp;
};

int main() {
	Knight* knight = new Knight();
	delete knight;
    //실행결과
    //new!
	//Knight()
	//~Knight()
	//delete!
}

이렇게 하면 new, delete를 사용할 때마다 우리가 원하는 명령어를 실행시켜줄 수 있습니다. 다만 이렇게 전역적으로 바꾸는 것은 원하지 않기 때문에 따로 함수로 만들어보겠습니다.

새로운 동적할당 함수 만들기

void* Alloc(int32 size) {
	return malloc(size);
}
void Release(void* ptr) {
	free(ptr);
}

template<typename Type, typename... Args>
Type* xxnew(Args&&... args) {
	Type* memory = static_cast<Type*>(Alloc(sizeof(Type)));
	return memory;
}

template<typename Type>
void xxdelete(Type* ptr) {
	Release(ptr);
}

int main() {
	Knight* knight = xxnew<Knight>();
	xxdelete<Knight>(knight);
}

이렇게 하면 새로운 동적할당 함수를 만들어줄 수 있습니다. 다만 생성자와 소멸자가 실행되지 않습니다. 왜냐하면 new와 delete는 알아서 생성자와 소멸자를 실행시켜주는 기능이 있지만 malloc과 free는 아니기 때문입니다.
그래서 생성자와 소멸자를 실행시켜주기 위해 명령어를 추가해줍니다.

template<typename Type, typename... Args>
Type* xxnew(Args&&... args) {
	Type* memory = static_cast<Type*>(Alloc(sizeof(Type)));
	//new(memory)Type(::forward<Args>(args)...);
	return memory;
}

template<typename Type>
void xxdelete(Type* ptr) {
	//ptr->~Type();
	Release(ptr);
}

이렇게 해주면 생성자와 소멸자도 잘 실행이 됩니다. 여기까지 새롭게 함수를 만들어 버그가 일어날 수 있는 부분 등을 보완할 수 있는 토대를 만들어보았습니다.

profile
안녕하세요. 컴퓨터를 공부하는 학생입니다.

0개의 댓글