TIL - 16(메모리 헤더, )

jh Seo·2024년 8월 20일

메모리 헤더

이전 TIL - 15에서 구현한 메모리풀에서 나아가 메모리 헤더를 구현해본다.

메모리 헤더

struct FMemoryHeader
{
	FMemoryPool* Pool = nullptr;
	int Flag = 0;
	int Flag2 = 0;
};

이렇게 생겨서 인자를 전해줄 때 사용 가능하다.

FClass2

class FClass2
{
public:
	FClass2()
	{

	}

	FClass2(const int InData)
		:Data(InData)
	{

	}

	FMemoryHeader* GetMemoryHeader()
	{
		FMemoryHeader* MemoryHeader = reinterpret_cast<FMemoryHeader*>(this) - 1;
		return MemoryHeader;
	}

	int Data = 0;
};

이렇게 FClass2에 GetMemoryHeader()함수가 있다.
설명은 FMemoryheader 호출 부분에서 할 것이다.

FClass3

class FClass3 : public FClass2
{
public:
	FClass3()
		: FClass2(10)
	{
		if (GetMemoryHeader()->Flag2 == 1234)
		{
			Data2 = GetMemoryHeader()->Flag2;
		}
		if (Data == 10)
		{
			// ...
		}
	}

	FClass3(const int InData)
		: FClass2(InData)
	{
		if (Data == 10)
		{
			// ...
		}
	}
	int Data2 = 0;
};

이렇게 FClass2를 public으로 상속받는 FClass3이 존재한다.

FMemoryHeader호출 부분

FMemoryPool MemoryPool{ sizeof(FMemoryHeader) + sizeof(FClass3), MaxCount };
void* Pointer = MemoryPool.malloc();
FMemoryHeader* MemoryHeader = static_cast<FMemoryHeader*>(Pointer);
new(MemoryHeader) FMemoryHeader();
MemoryHeader->Pool = &MemoryPool;
MemoryHeader->Flag2 = 1234;

FClass3* Class = reinterpret_cast<FClass3*>(MemoryHeader + 1);
new(Class)FClass3();

FMemoryHeader* MemoryHeaderPos = reinterpret_cast<FMemoryHeader*>(Class) - 1;
MemoryHeaderPos->Pool->free(Class);

Memory Header을 생성, 호출해주는 부분이다.
일단 MemoryPool을 새로 생성해준다.
FMemoryHeader의 사이즈 + FClass3의 사이즈를 chunksize로 잡고, 청크 갯수는 MaxCount 백만개다.
여기서 MemoryPool.malloc을 통해 chunk만큼 할당된 void* 형 포인터 Pointer를 받고 ,
Pointer을 일단 FMemoryHeader* 크기만큼 static_cast를 이용해 MemoryHeader에 할당해준다.

FMemoryPool MemoryPool{ sizeof(FMemoryHeader) + sizeof(FClass3), MaxCount };
void* Pointer = MemoryPool.malloc();
FMemoryHeader* MemoryHeader = static_cast<FMemoryHeader*>(Pointer);

placement_new를 통해 MemoryHeader주소에 FMemoryHeader()객체를 생성해준다.
그리고 해당 객체에 Pool과 Flag를 넣어줬다.

new(MemoryHeader) FMemoryHeader();
MemoryHeader->Pool = &MemoryPool;
MemoryHeader->Flag2 = 1234;

그리고 해당 MemoryHeader 포인터에서 +1을 하게 되면 FMemoryHeader의 크기만큼 넘어간 주소가 된다.

reinterpret_cast로 해당 주소를 FClass3*로 변경 후, placement_new 를 통해 해당 주소에 FClass3객체를 할당해준다.

FClass3* Class = reinterpret_cast<FClass3*>(MemoryHeader + 1);
new(Class)FClass3();

이렇게 메모리헤더를 구현하게 되면, 위 FClass2, FClass3에서 인자를 쉽게 사용이 가능하다,
FClass2에 구현된

	FMemoryHeader* GetMemoryHeader()
	{
		FMemoryHeader* MemoryHeader = reinterpret_cast<FMemoryHeader*>(this) - 1;
		return MemoryHeader;
	}

이 함수에서 호출하는 this는 FClass2의 주소를 가리킨다.
하지만 FClass3이 FClass2를 상속받는 상황이므로 FClass3의 this포인터 주소는
FClass2에서 호출한 this포인터 주소와 같다.

해당 주소에서 FMemoryHeader크기만큼 -1해주면 FMemoryHeader의 주소를 반환하게 된다!

따라서 FClass3에서

if (GetMemoryHeader()->Flag2 == 1234)
{
	Data2 = GetMemoryHeader()->Flag2;
}

GetMemoryHeader()함수를 호출해 MemoryHeader에 접근할 수 있게된다!!

unordered_map insert 반환값

pair<iterator,bool> insert ( const value_type& val );

위와같은 형태의 insert를 사용하는데 반환형이 궁금해 찾아봤다.
여기서 반환형은 pair<iterator,bool>인데 first값은 방금 inser한 원소를 가리키는 iterator이고, second는 insert가 성공했는지 여부이다.

unordered_map에서 value_type은

Member type value_type is the type of the elements in the container, defined in unordered_map as pair<const key_type,mapped_type>,

key, value 형태의 pair타입이라고한다.

profile
코딩 창고!

0개의 댓글