이전 TIL - 15에서 구현한 메모리풀에서 나아가 메모리 헤더를 구현해본다.
struct FMemoryHeader
{
FMemoryPool* Pool = nullptr;
int Flag = 0;
int Flag2 = 0;
};
이렇게 생겨서 인자를 전해줄 때 사용 가능하다.
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 호출 부분에서 할 것이다.
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이 존재한다.
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에 접근할 수 있게된다!!
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타입이라고한다.