게임을 만들던 도중  STL list로 관리하는 오브젝트가 삭제될때 list 오류가 나는것이다.. 


나는 list를 잘 사용을 못해 진짜 꼼수로 오류를 막았는데 그 방법이



오류코드

for (auto Iter : m_objects)

{

for (auto Iter02 = (*Iter.second).begin(); Iter02 != (*Iter.second).end();)

{

if ((*Iter02)->GetDelete())

{

SAFE_DELETE(*Iter02);

         (Iter.second)->erase(Iter02);

}

else

Iter02++;

}

}

여기서 m_objects는 STL map 이다. map<int key, list<cGameObject*>*> 이런 방식이다

예를 들면

 



위 코드의 문제는 만약 GetDelete함수가 참이되는 오브젝트를 삭제하고나면 그 Iter02는 삭제되어 다음 object를 가르키는 iterator가 없어지는 것이다 그리고 나서 삭제된 Iterator의 접근하니 오류가 날 수 밖에 없는 코드이다

 

 나는 list를 잘몰랐기 때문에 하나를 삭제하고 break 를 써서 안쪽 루프를 탈출하는 방법을 쓰고있었다.


바로 이렇게


꼼수식 해결코드(꼼수라고도 못한다)

for (auto Iter : m_objects)

{

for (auto Iter02 = (*Iter.second).begin(); Iter02 != (*Iter.second).end();)

{

if ((*Iter02)->GetDelete())

{

SAFE_DELETE(*Iter02);

         (Iter.second)->erase(Iter02);

 break;

}

else

Iter02++;

}

}


위 코드는 문제하나가있다 하나가 삭제될때마다 삭제된 오브젝트와 같은 key값의 list의 저장되는 object들은 현재 프레임에서 삭제를 못하고 다음 프레임에서 삭제를 해야하는 경우가 발생한다.(그냥 삭제된 오브젝트와 같은 키값 list의 저장된 오브젝트는 삭제를 계속 미루는 것이다 이게 계속 쌓여서 삭제가 느리게되는것이다.

이 문제는 내가 뭔가 위 코드가 이상하다고 느껴서 총알 발사 속도를 엄청나게 빠르게해놓고 계속 발사하다보닌까 삭제가 늦게되는 총알이 발생한다는것을 알게되었다.


인터넷의 이유를 검색하닌까 이유를 알게되었다 그 이유는


위에서도 설명했지만 삭제가 실행되는 Iterator가 삭제되면 다음 값을 가르키는 Iterator가 삭제되는 것이기 때문에 다음값의 접근을못하고 삭제된 iterator의 접근을해서 오류가 나는것이다.


이것의 해결방법은 

만약 list.erase() 를 이용하여 삭제되면 erase함수는 삭제된 Iterator의 다음 Iterator를 리턴한다. 이것을 이용하면


for (auto Iter : m_objects)

{

for (auto Iter02 = (*Iter.second).begin(); Iter02 != (*Iter.second).end();)

{

if ((*Iter02)->GetDelete())

{

SAFE_DELETE(*Iter02);

         Iter02 = (Iter.second)->erase(Iter02);

}

else

Iter02++;

}

}



이렇게만 해주면 삭제할때마다 break를 써서 탈출하여 삭제할 오브젝가 쌓이지 않고 계속 삭제된 오브젝트와 같은 list의 저장된 object들도 조건이 참이되면 계속 삭제가 될 수 있다.




개인이 공부하는 목적으로 올린 포스트이기 때문에 틀린 내용이 있을 수도 있습니다 댓글로 알려주세요



'programing > c_c++' 카테고리의 다른 글

Win32프로젝트에서 콘솔창 이용하기  (0) 2018.02.15

Win32로 프로젝트를 진행하다 보면 여러가지 상태의 변경상황을 확인해야하는데 이런 것을 디버그로 확인 하다보면 정말 불편하다 멈추고 확인하고 멈추고 확인하고... 계속 반복하다 보면 정말 귀찮다 그리고 프로그램의 특정 상황(게임같이 계속 프레임이 돌아가는 경우) 에서 확인 해야 한다면 거의 불가능한 수준이다. 


그래서 Win32에서도 콘솔창을 띄울 수 있는 방법이 있다


프로그램 시작시 이런 코드를 추가해주면 된다


#pragma comment(linker, "/entry:WinMainCRTStartup /subsystem:console") 


하지만 또 확인해야 할 것이 있는데 자신의 프로그램이 멀티바이트를 사용하는 프로그램인가 유니코드를 사용하는 프로그램인가에 따라서 코드가 조금 다르다


유니코드 사용시

#pragma comment(linker, "/entry:wWinMainCRTStartup /subsystem:console") 


멀티바이트 코드 사용시

#pragma comment(linker, "/entry:WinMainCRTStartup /subsystem:console")  


이렇게 코드를 달리 해주면 된다


근데 이걸 또 프로젝트 생성시 마다 확인해주고 다르게 작성하기 귀찮으니

c/c++인 경우 배운 전처리 지시기를 이용하면 편리하다


                                                                                                           

#ifdef UNICODE                                                                                      

      #pragma comment(linker, "/entry:wWinMainCRTStartup /subsystem:console") 

#else                                                                                                    

      #pragma comment(linker, "/entry:WinMainCRTStartup /subsystem:console")   

                                                                                                           


이렇게 해주면 확인해줄 필요도없고 또 확경이 바뀌어도 알아서 해주니 편리하다


그리도 대부분 디버그 모드에서만 활용하니


#ifdef _DEBUG

                                                                                                           

#ifdef UNICODE                                                                                      

      #pragma comment(linker, "/entry:wWinMainCRTStartup /subsystem:console") 

#else                                                                                                    

      #pragma comment(linker, "/entry:WinMainCRTStartup /subsystem:console")   

#endif                                                                                                   

#endif                                                                                                   



이렇게 해주면 된다 그리고 프로그램 상에서 cout이나 printf 를 사용하면된다


(개인이 공부목적으로 쓰는 글이기 때문에 틀린 부분이 있을 수 있습니다)

'programing > c_c++' 카테고리의 다른 글

STL list 원소삭제법.  (0) 2018.02.24

directX 게임 프로그래밍을 공부하던 중 UI를 만들때 쓴 LPD3DXFONT이다.


사용법

1.  D3DXFONT_DEST 구조체를 초기화해준다 (LPD3DXFONT를 쓰기 위해 설정하는 구조체 같다.)

D3DXFONT_DESC dese =

{

50, 0

, FW_BOLD, 1, FALSE

, HANGUL_CHARSET

, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, FF_DONTCARE

, TEXT("양재블럭체")

};

   

   

아는 것만 써본다.(D3DX에서 가져옴)

   

INT Height; // 글자 높이

   

 UINT Width; // 글자 폭

   

 UINT Weight; // 폰트의 굵기 (현재 설정된것은 FW_BOLD = 굵음)

FW_THIN                얇은

FW_NORMAL           보통

FW_SEMIBOLO        조금 굵게

FW_EXTRABOLO      많이 굵게


 UINT MipLevels;   

 BOOL Italic;

 BYTE CharSet;    

 BYTE OutputPrecision;

 BYTE Quality;

 BYTE PitchAndFamily;

 WCHAR FaceName[LF_FACESIZE]; // TEXT("양재블럭체) : 폰트설정.



2. LPD3DXFONT 를 만들어준다

D3DXCreateFontIndirect(g_Device, &dese, &m_Font2);

// 각각 디바이스 , 설정구조체 포인터, LPD3DXFONT 포인터


3. 화면에 쓴다

m_Font->DrawText(sprite, string, count, &drawPos, DT_NOCLIP, color);

// 각각 sprite객체 , 

출력할 문자열(LPTSTR), 

문자의 갯수(int), 

위치(RECT ->left : x , top : y 나머지는 0(DT_NOCLIP을 쓴다면) ) , 

출력 플레그(현재 플레그는 사각영역을 넘어가도 자르지 않는다. ),

글자색






'programing > directX' 카테고리의 다른 글

DirectX D3DXVec3TransformCoord와 D3DXVec3TransformNormal 함수  (0) 2018.10.15
LPD3DXMESH 쓰는법  (0) 2018.10.13

+ Recent posts