이런 지랄같은 STL iterator
map<int, int> fuckingstl;
fuckingstl.insert(make_pair(100, 100));
for (map::iterator pos = fuckingstl.begin(); pos != fuckingstl.end(); ++pos)
{
map::iterator next = pos;
--next;
if (next != fuckingstl.end())
cerr << "18181818" << endl;
}

남이 짠 코드를 좀 고치고 있다. 좀 코드가 거시기 하더라도 이해 해주셈. 이 코드를 돌렸을 때 18181818이 나와야할까? 안나와야할까? VC++의 STL 구현에서는 욕이 안나오는데 리눅스 gcc에서는 욕이 튀어나온다.

map에 원소가 하나만 있고, pos가 맨 첫번째 원소를 가리키고 있을 때, -- 연산을 주면? gcc STL은 그대로 머무르고 VC++ STL은 싸이클을 그려 맨 끝 원소를 가리키도록 되어있다. 이 행동이 달라 두 플랫폼에서 결과가 다르게 나와 한참을 삽질 했다.

원래 코드의 의도대로라면 VC++ STL의 방식처럼, 즉 한 바퀴 돌아 end를 가리키는 것을 가정하고 만들어진 코드다. VC++에서는 문제가 없던 것이 gcc로 돌리니 이상한 현상이 종종 벌어졌고 그 이유가 바로 이런 예외 상황에서의 사소한 iterator의 -- 연산 정책 때문이었다. 문제는 원래 이 소스 코드가 리눅스 위에서 만들어 졌다는 점. 참고로 gcc는 버전이 3.4.6, VC++은 2008에서 돌린 코드.

이거때매 몇 시간 날린거지. 도대체 어떤 행동이 정확한 것일까요?

오늘의 교훈: STL 구현마다 이렇게 미묘한 행동 차이가 있다.

by object | 2008/05/16 17:21 | 컴퓨터 | 트랙백 | 핑백(2) | 덧글(18)
트랙백 주소 : http://minjang.egloos.com/tb/1891481
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Linked at 미친병아리가 삐약삐약 : 20.. at 2008/06/11 17:54

... 기인데.. 이 사람 이렇게 안 봤는데, 무슨 이야기를 이렇게 하시나.. 144. 손수건이 필요하다. 안타까운 현상이다.. 국내 영화계가 한때 번창기를 맞는가 싶더니.. 이런 지랄같은 STL iterator STL을 사용하면 장점 중 하나가 여러 환경에서도 코드를 고치지 않고 사용할 수 있다는 것인데, 이런거 보면 완벽하지 않은 부분이 더 많다.. 가장 근접한 것은 ... more

Linked at art.oriented : g.. at 2008/07/28 17:21

... 이전 글에서 VC++/gcc 두 플랫폼 STL의 map iterator 작동이 달라서 불만을 토로 했었다. 문제는 iterator가 맨 첫번째 원소를 가리키고 있을 때, -- 연산을 ... more

Commented by XJeongseok at 2008/05/16 17:35
저도 한창 STL쓰고 있는데요. ㅎㅎ
이터레이터 써서 for문 돌리는거 재밌네요. 물론 저는 VC++만 써서 이런 차이점은 모르고 있었는데, 이런 차이도 있네요.
Commented by object at 2008/05/16 17:39
STL이 플랫폼마다 똑같이 돌아가겠다고 생각했다간 큰일나... 뭐 이미 hash_map 같은 거야 워낙 구현이 달라서 익히 알고 있었지만 이런 이터레이터의 행동에도 차이가 있을 줄이야..
Commented by eslife at 2008/05/16 20:04
근데 이렇게 코딩하는 사람도 좀 뵨태가 아닐까요. 역으로 돌아간다는고 생각조차 않하는 사람들이라면 코드 보면서 어지러울 것 같습니다. (제가 어지러워요ㅠㅠ)
Commented by lifthrasir at 2008/05/16 20:18
애초에 정의되지 않은 행동 아닌가요? C++ 표준에는 bidirectional iterator의 행동에서 --it는 오로지 it == ++prev인 prev가 존재할 때만 정의된다고 되어 있네요. (ISO/IEC 14882:1998 24.1.4) 그것과는 별개로 구현하는 벤더들의 입장에서라면 VC++의 행동이 더 바람직하지 않을까 싶습니다...
Commented by lifthrasir at 2008/05/16 20:20
위에 댓글 잘못 썼네요. 아무 짓도 안 하는 gcc의 행동이 더 바람직하겠습니다. -_-; (아무리 생각해도 반대로 reachable하다는 건 정의 안 된 행동이라 하더라도 그다지...)
Commented by object at 2008/05/16 20:39
표준까지 찾아주시고 정말 감사합니다.

네, 아마 표준에는 그런식으로만 정의가 되어있고 그 이외의 경우에는 말그대로 undefined으로 남겨둔 것 같습니다. 그러니 벤더들이 어떻게 구현하든 자기 마음이겠죠. 굳이 어느 쪽이 더 옳다라고 말하기는 조금 힘들 것 같습니다. 어떤 경우는 뺑뺑 도는 것이 좋을 수도 있고 (이런 것을 가정하고 코드를 짜면 그 만큼 코드에서 조건문이 줄어들 수 있습니다. 바운더리 첵을 줄이기 위해 막 sentinel node도 두고 그러죠.), 반대로 gcc처럼 더 못내려갈 때는 계속 그 자리에 머무는 것도 또 좋을 때도 분명 있을 것입니다.

아쉬운 건 이렇게 표준에서 정의되지 않은 행동을 시도할 때 뭐라도 exeception이나 경고라도 띄어야하는데 그냥 조용히 실행이 된다는 점입니다. 이거 밝혀내는데 시간이 꽤 걸렸거든요. 세부적인 STL을 몰랐을 때, 비효율적인 코드가 만들어지는 것은 괜찮습니다. 그런데 부정확한 코드가 만들어지는 것은 분명 문제가 있죠.

이 코드가 좀 복잡한 플로우를 다루고 있는 것이라서.. 앞으로 가는 경우가 희한하게도 있습니다 =.= 저런 것을 왜 undefined로 놔뒀는지 좀 의아하네요. 정말 익스트림한 케이스도 아닌데.. 흑..
Commented by 고어핀드 at 2008/05/16 22:18
(코드 보다가 뿜은 1人)
Commented by xeraph at 2008/05/17 00:15
"18181818" (..)
Commented by flexy at 2008/05/17 02:32
이런 미묘한 차이를 이해하지 못해 한참을 삽질할 때가 종종 있죠. 이게 또 프로그래밍의 재미죠? 언제 어디서 이런 변수가 튀어나올 지 모르는 것.
Commented by object at 2008/05/17 10:12
저 미시적으로 미묘한 차이가 거시적으로 대단한 행동 오류를 낳아 개삽질 했죠 ㅠㅠ
Commented by 캐리 at 2008/05/17 13:41
ㅎㅎ 뭐 사실 map에서의 iterator자체가 그닥 직관적이지 않고 잘 안써봐서 모르겠지만 하여간 미묘한 차이가 있네요
사실 C++의 경우 undefined behavior때문에 고통스러운 순간이 꽤나 자주 발생하죠. 사실 표준을 달달 외우는것은 불가능 하지만, 그래도 웬지 조금이라도 미심쩍은 부분은 표준을 한번씩 확인해 보아야 할 것 같네요..
Commented by eoh at 2008/05/18 01:18
iterator 의 환형구조를 보장하지 않는것은 너무도 당연해서 주의해두지 않은것 같네요.

배열에 대해서 환형구조를 보장하지 않듯이.. 그걸 모델로한 iterator 도 보장하지 않는게 당연합니다.
그리고 보장하지 않는 행동에 대해서, 표준에서 아무것도 하지 않는다는 정의와, 아예 언급이 되지 않은 행동이 있는데, 후자는 문법 외의 사용으로서 assertion 이라도 해주도록 만들어야 하는게 예의죠..

저는 이렇게 생각합니다..
VC++ 은 쓸데없는 짓을 더 했거나 (괜히 마지막요소로 가도록 따로 만들었거나..),
딱히 막지 않았다는것. (이용하는 자료구조가 환형이라, 처음으로 돌아가는걸 막지 않은것..)
어느쪽인지는 제가 VC++이 없어서 잘 모르겠고요..
GCC 는 순수하게 이동범위를 벗어나는것을 막아두었다는것.

저는 대체로 디버그모드에서, 경계를 벗어나면 경고창을 띄우는 정도로 만들고 있지만요..
Commented by object at 2008/05/18 05:23
희한하네요. gcc/vc++ 모두 -- 증감 연산은 거의 비슷하고 (앞 부분 nil 체크하는 것 빼곤 동일) 모두다 환형으로 도는 것이 정확한 구현입니다.

map에다가 원소를 3~4개 넣고 it를 계속 -- 해주면 gcc/vc++ 모두 루프를 돕니다. 그런데 gcc에서는 원소 하나만 있을 땐 --가 루프를 돌지 않네요. 이거 버그인가요?
Commented by zelon at 2008/06/03 17:13
재미있네요. STL collection 이 원형이라는 생각은 해본적도 없어서 begin() 에서 -- 할 생각도 못해봤는데, 다행(?)스럽게도 정의되지 않은 동작이었군요. -_-;;
Commented by 궁금해서 at 2008/07/28 15:53

GCC 행동이 더 바람직해보이네요

hash를 저런식으로 코드 짜는거 자체가 , 기본적인 상식을 가진사람이 짰다고 보기 힘들다고
느껴집니다

비표준인 만큼 최대한 이상한 코드를 덜짜도록 노력해야할테넫.. 어찌 저런 for문을 짠답말입니까?
Commented by object at 2008/07/28 17:23
제 실험 결과로는 gcc 구현이 버그입니다.

그리고 map은 hash table이 아닙니다. Binary search tree이기 때문에 저런 for는 기본적인 상식을 가진 사람이 짠 코드가 맞습니다.
Commented by penzal at 2008/07/29 17:58
'한 바퀴 돌아 end를 가리키는 것을 가정하고' -> 요 가정이 문제의 소지가 있는 것이고,
표준으로 정의되지 않은 동작에 관해서는 컴파일러의 차이를 인정해야겠지요.

표준이 아닌 것들을 유연하게 처리해줘서, 우리가 표준인것으로 알고있는 것들이 꽤 될거라 생각하지만,
개인적으로는 어설션을 내 주는 것이 가장 좋더군요.
Commented by object at 2008/07/30 02:45
행동이 이렇던 저렇던 상관은 없는데 최소한 일관성이 있어야하죠. gcc map 이터레이터는 비록 표준에 명시되어있는 상황은 아니지만 예외 상황에서 일관성이 없었습니다. 핑백된 글에 자세한 실험 결과가 있습니다. 말씀대로 어설션이 가장 좋습니다..

:         :

:

비공개 덧글

<< 이전 페이지 다음 페이지 >>





by 김민장 2008 이글루스 TOP 100
최근 등록된 덧글
개발자 입장에서의 수많은 ..
by Jiyoon at 02/04
저도 아들 돌잔치때 돌잡이 ..
by 박상욱 at 01/18
미국 대학원 원서 작성중에 p..
by 태클사이야 at 01/13
TO: 박PD 로그인 하지 않아..
by 박응용 at 01/10
http://gigglehd.com/zbx..
by dhunter at 12/28
우와.. 좋네요. 태반이 ..
by 윤광배 at 12/17
항상 좋은 글 잘 보고 있습니..
by y2k at 11/23
글이 좋아서 제 블로그에 담..
by 쏭섭 at 11/23
최근 등록된 트랙백
조엘 스폴스키의 강연 (Sta..
by 인덕원칸타타
[Redis] sds.c를 분..
by 조급하지말고 천천히
메뉴릿
이글루 파인더

website counter

Add to Google

rss

skin by 이글루스