삽질로 배우는 STL? 해답편 ... -_-

삽질로 배우는 STL 기초 개념? 의 解편입니다.

이전 글을 보시지 못한 상태에서 내가 스스로 코드의 버그를 밝혀내겠소 같은 생각을 하는 분이 계시...려나 모르겠군요. -_-;
그런 분은 이전 글만 읽어보시면 되겠습니다.



여튼 정답을, 자타공인 코딩의 신 아샬 님께서 매우 가볍게 맞추어 주셨습니다.
상품으로 특별히 제 블로그 1년 정기구독RSS를 증정!
필요 없다구요? 넵 지성 _-

아무튼 해설편입니다.
문제편의 소스 코드 전부를 인용...하지는 않겠습니다.
			AddData(vecFoo, p);
ASSERT(&p == &vecFoo[i]); //
p.dwType += 10;
힙 메모리가 깨지는 원인은 바로 저 부분에 있었습니다.
  1. Foo &p = vecFoo[i];로 벡터 내 원소 중 하나의 메모리를 직접 참조하고 있던 상황에서,
  2. vecFoo에 push_back이 이루어집니다.
  3. 기본으로 할당되어 있는 사이즈 이하일 때 추가되는건 아무 문제가 없는데,
    루프를 돌면서 벡터 크기가 더 커지게 되면서 vector STL이 할당 영역을 늘리는 작업을 시도하게 됩니다.
    물론 이때의 작업은 새로 더 많은 메모리를 할당해서 거기에 기존 데이터를 복사해넣고, 기존 할당 영역은 날려 버리는 것.
    이 작업이 일어나면서, &p가 가리키는 것은 더이상 vecFoo[i]가 아닌 엉뚱한, 이미 자연으로 돌아가 중천을 떠도는 무언가...가 되어버리는거죠. 그게 뭐 어쨌냐고 물으신다면 그저 웃을 수 밖에 없지만서도 뭐랄까,
    이를테면 자길 버리고서 더이상 아무 상관 없게 된 남편이 곧장 다시 와서는 '그래도 네가 필요해'라며 자신의 몸을 더듬으면, 님 같으면 기분 좋겠어여?!
    버릴땐 언제고 이제 와선 또 뭐하는거야, 어이 거기 내 힙 건들지말라구!! 하고 힙 에러를 내는 사랑과 전쟁...스러운 그런 가슴 아픈 스토리...가 펼쳐진 것을 목격한거죠 우리는... ... -_-;;

아무튼;;;
설령 힙 에러를 내지 않는다 하더라도, &p에 들어간 값은 vector가 메모리 재할당 작업을 하는 순간 근거를 알 수 없는 값이 되어버립니다. 그렇게 되면 코드는 문제 없이 넘어갔다 해도 왜 이상한 값이 난데 없이 들어가 있나 하고 골머리를 썩히는 그런 일이 생기게 될테지요, 그렇게 되면 왜 데이터가 이상해지는걸까 원인을 몰라 코드 전체를 쑤시고 다녔을...지도 모른다고 생각하니 조금 무섭다... -_-;;;

아무튼 이 사건은 vector, deque은 포인터 덜 신경 써도 되니 좋은 것 같넹, 이라고 생각하고서 생각 없이 STL에 기대다가 보기 좋게 당한 꼴보기 좋은 케이스였습니다.
vector나 deque 같은 계열은 배열내 원소들의 수가 늘거나 줄어들거나 하는 경우 운 좋게 무효가 되지 않는 경우도 있지만 대부분 무효가 될거라고 상정해두고서 작업하는 것이 좋을 것 같습니다. 특히 멀티 스레드 기반 프로그램이라면 벡터 원소에 대한 포인터를 걸어놓고서 먼 미래에 참조하는, 그런 일이 생기지 않도록 더욱더 조심해야겠지요.


아 간만에 어딘지 모르게 영양가 있어 보이는 글을 적어보았더니 기분이 좋근영. ( -_-)
영양가 있는 부분이 어딘지 모르겠다... 는게 문제지만. ( -_-);;;;

by nvu | 2007/12/28 10:34 | 트랙백 | 핑백(1) | 덧글(2)

삽질로 배우는 STL 기초 개념?

제목이 낚시...인듯한데 생각나는 제목이. -_-;

다음은 버그가 있는 코드입니다. 버그의 원인을 찾아보세요.
inline void AddData(vector<Foo>& vn, Foo& fu) 
{
vn.push_back(fu);
}

{
vector<Foo> vecFoo;
//...
//적당히 vecFoo에 개체를 채워넣는다.
//
size_t n = vecFoo.size();
for (size_t i = 0; i < n; ++i) {
Foo &p = vecFoo[i];
if (p.dwType < 10) {
AddData(vecFoo, p);
p.dwType += 10;
}
}
}

분명, 테스트할 때만 해도 아무 문제 없던 프로그램.
그런데 실제로 프로그램이 실무에 들어가자 프로그램이 죽어버리는 치명적인 에러 발생.
확인해보니 테스트 때 vecFoo에 들어있는 개체 수를 500개 정도 넣어두고 저 루프에 들어가면 아무 문제가 없는데, 몇개라고 단정 지어 말할 수는 없지만 일정 갯수... 그러니까 한 600개 쯤? 이상이 되니 힙이 깨지는 에러가 발생하는 것이었다.

도대체 나는 무엇을 잘못한 것일까요?

힌트 :
vecFoo를 선언한 후, vecFoo.reserved(10000); 식으로 미리 vecFoo에 들어갈 최대갯수 이상으로 영역을 넉넉하게 할당해보니 문제가 발생하지 않았음.
하지만 이게 궁극적인 해결책이라고는 보이지 않는데에에...?



음음; 먼 예전에 짜놓고는 오늘에야 힙 깨지는거 확인하고 수정한 버그였습니다. 그래도 원인을 금방 찾아냈으니, 기분은 상큼.
뭐. 인터넷이란건 참 좋은 것 같습니다.
굳이 게시판에 질문을 적지 않더라도 조금만 머리 굴려 검색해보면 문제의 실마리를 찾아낼 수 있으니까요.

... 아무튼 오늘의 삽질 로깅이었습니다.

정답은 다음 이시간에! ... 랄까 음 저와 비슷한 경험 하신 분이 계실 것 같기도 한데 말이죠.

by nvu | 2007/12/27 14:25 | 트랙백 | 핑백(2) | 덧글(4)

2008 D6 rub-y!

네, 오늘이 바로 연말정산 두번째 시간이빈다. 오늘은 엔뷰가 진행하던 개인 프로젝트에 대한 이야기를 해보져 ... ㅇㅇ
네, 그래도 어쩐지 프로그래머이긴 했던 모양이거덩여... ㅇㅇ;;;


상당히 지지부진하게 만들어지고 있었던 개인 프로젝트, BMS 플레이어 rub-y!가 그럭저럭 본 궤도에 올라와 쓸만한 녀석으로 다듬어진, 그런 한해였다.

작년에는 D3D7 기반으로 만들어지던 것을 640x480 해상도에서 800x600 해상도로 느닷없이 올리느라 시간을 다 써버렸는데;
올해에는 일부 PC들에서 D3D7의 컬러키 기능이 먹질 않아서 홧김에 D3D9 기반으로 처음부터 라이브러리 전체를 다시 만들고,
또 얼마 전에는 렌더링 부분도 다시 갈아 엎고,
얼마전에는 BMS 목록 관리에 SQLite를 가져다 붙이는 등(-_-) 이런저런 삽질에 삽질을 거듭한 상태.

어쨌든 처음 만들어보자 하고 삽을 뜬 것이 2003년 1월(가장 오래 전에 변경된 파일 날짜가 그거긴 한데 확신은 서지 않음ㅇㅇ;)인데 아직도 붙잡고 있다니 지겹지도 않나... 내지는, 아직도 붙잡고'는' 있다니, 오오 내자신의 인내력은 참 킹왕짱인듯...이라고 해야할지, 아니 자기가 무슨 파이브스타스토리 쓰는 나가노 마모루인지 알고 있나 언제 다 만들래 ㅅㅂㄹㅁ 싶다고 해야할지(...) 이런저런 만감이 교차하는데.

프리랜서를 가장한 날백수 시절이었던지라 베이스 스킨을 직접 만들고 나서 나중에 그 스킨에 맞게 그래픽을 부탁했던 리듬잇과는 달리, 직접 이것저것 다 챙기기에는 아무리 봐도 무리였던지라 rub-y!는 처음부터 그래픽 작업을 다른 분과 함께해서 작업.
이 작업을 함께 해주신 분이 바로 nt02님. 굉장히 많은 고생을 하셨는데;;
아무래도 1인 제작과는 달리 성격이나 지향점이 다른 두 사람이 함께 제작하다보니;
의도상 일치하지 않는 부분들이 의외로 있었다랄까.
이를테면 특정 오브젝트를 가리키는 표현이 서로 다르다든가 하는 것부터.
설명을 나름 잘한다고 했는데 에엥이다 싶은 결과물이 돌아왔다거나
아직 갈길이 먼데 서로 초울트라 스펙타클한 기능을 망상하면서 놀고 있다거나(...)
그리고 내가 의도하고 있던 화려함도 좋지만 솔리드한 느낌 유지가 우선 이라는 것과
nt02님이 지향하고 있던 화려함을 강조한 디자인은 아무래도 양립할 수 밖에 없는 부분인지라
이러한 느낌을 서로 적절하게 조율한다는건 의외로 쉽지 않은 일이었다.
그런 리테이크 요청을 꿋꿋하게 받아 넘겨주신 nt02님은 과연 대인배. ㅠㅠ
저 보기 싫어서 저 차단 거신거죠? 그래서 메신저에서 안보이시는거죠? (농담-_-;)

다시 소스 이야기로 돌아와서 아무튼 이 정도면 꽤 많은 양을 두드렸구나 싶어서 통계를 내보니 기껏 소스 코드 용량 1.2MB. 5년동안 하루에 스페이스랑 탭 포함해서 영자 690자 두드리고 IDE 닫았...다는 통계가 나와 버리니 어쩐지 암울...하지만-ㅅ-;;
델파이나 VB스크립트만 만져서 녹스는 듯한 C++ 같은 쪽에 대한 감각도 계속 유지한다는 차원에서 그런 삽질이 시간낭비였다거나, 하는 종류의 생각은 들지 않아서 다행인듯 하다.

그러나 다시는 반복하지 않겠다고 마음 먹었던 소스 코드의 스파게티 화는 대략 답이 없음.
어쩌다 이렇게 됐는지 물으셔도 드릴 말씀이 없어요ㅠㅠ
설계 같은걸 안하고 닥치고 코딩이니까 그렇겠지만 그래도 BMS플레이어 처음 짜보는 것도 아닌데ㅠㅠ

BEMANI 10주년은 BM98 즉 'BMS계의 10주년'이기도 하다. 이래저래 의미 깊은 해라고 할 수.. 있을지 모르겠는데.
여튼 2008년에도, '어디까지나 취미니까' 하는 자기 위안으로 꾸준히 게속 만들어 볼 계획.
여전히 시도해보고 싶은 기능이나 아이디어 같은 것도 많이 남아 있고.

by nvu | 2007/12/26 17:57 | 트랙백 | 덧글(0)

◀ 이전 페이지          다음 페이지 ▶