2008.10.08 11:13 책 정리/Exceptional C++

두 개의 포인터가 같은 객체를 가리키고 있는지 그 판단을 하기 위한 알고리즘을 제시하는 항목이다.

다음의 코드 this != &others 검사는 자기 할당을 피하기 위한 기본 방법이다. 과연 이 조건절만으로 자기 할당을 피하는게 가능할까? 그렇지 않은 경우와 어떻게 고칠 수 있는지 알고리즘을 만들라.

문제 : 정말로 이것으로 자기 참조를 피할수 있을까? 피할수 없다면 어떻게 고칠 수 있을까? 고칠 수 있다면 그 알고리즘은 어떻게 만들어 졌는가?

나는 이 항목을 시작하기 전에 한가지 생각에 빠지게 되었다. "자기 대입이 왜 나뻐? 자기 대입 되던말던 자기 자신의 값은 계속 가지고 있는거 아니야?" 라는 생각에 말이다. 그래서 아래 코드로 짠 다음 무슨 문제가 있을지 생각해 보았다.


역시 별 문제가 없이 잘 되었다. 그리고 기본 자료형도 되니까 포인터도 해봐야겠다. 생각하고 코드를 짰고, 다음 코드가 나오게 된다.


.. 눈치 빠른 사람은 이런 생각하기도 전에 .. 그럴수도 있겠군 생각하게 된다. 바로 복사 할당 연산자의 경우, 포인터라면 기존의 값을 날리고 새롭게 받아야 되는 구조로 가야 한다는 것이다! 이건 절대적인 것이다. 그런데 이걸 어쩌지? 이미 나 자신을 날려버렸는데?

물론 날릴 필요가 없는 구조라면, 자기대입에 대한 처리 따위는 없어도 된다. 하지만 이렇게 살다가 언젠가 그러다 큰 코 다친다라는 격언을 곱씹어야 할지도 모른다. 왜냐.. 습관 자체가 안되어 있기 때문이다.(물론 .. 습관이 안되어 있어도, .. 뭐~ 할 사람은 다 하더라..)

그렇다면 이제 슬슬 자기 대입을 처리하는 방법과 이 방법을 통해 알고리즘을 알아 보자.


이렇게 코드를 짜게 되면, 자기 복사에 대한 검사를 하지 않아도 되고, 또한 예외 안전성 또한 갖게 된다. 이 알고리즘을 뜯어 보면 다음과 같다.

  1. 임시 객체를 생성한다.
  2. 그곳에 작업을 한다. 작업 중 예외가 발생하면 예외 보고 또는 예외를 삼킨다.
  3. 나 자신과 임시 객체를 교환한다.

이 알고리즘을 보면, 만화책 해왕기의  "판 감마 비젠"을 생각나게 한다. 적절히 익을 때 까지 기다렸다가, 낼름 받아 먹는 행동이 똑같다. 여기서 적절히 익을 때까지가 번호 2번이 완료될때고 낼름 받아 먹는 행동이 번호 3번이다.

하지만 이 구조가 과연 좋을까? 그건 절대 아니다. 분명 매우 간단하고 매우 좋은 예외 안전성까지 갖추었으나, 성능의 입장에서 보면, OTL 이다. 성능의 입장이라 말하면 무슨 성능 하겠다 싶어 다음 코드를 포함 시킨다.


이 코드의 라인 9를 보자. 아무리 판 감마 비젠이라 할 지라도, 성능앞에선 울고 도망칠 것이다. 그래서 STL vector 제작자는.. 할당 연산자의 세부구현에 자기 복사 검사를 포인터로 한다.

이제 슬슬 정리가 된다. 왜 자기 복사 대입이 위험한지? 어디서 임시 객체 생성과 교환 알고리즘이 무너지는지? 어떻게 성능을 향상 시킬지에 대한 실마리를 알게 된다!

그럼 이제 성능 향상 실마리를 통하여 어떻게 안전적이고 확고한 검사를 할 수 있는지 알아보자.

성능 향상은, if 문을 통하여 자기 검사를 해야 한다. 즉 다음과 같은 코드에서 처럼..


눈치 빠른 사람은 어?? 어??? 그럴지도 모른다. ^^ 자세히 보면 복사 생성자에서 .. 자기 복사를 검사 하는데, this 는 자신의 주소가 들어온것은 자기 자신인데, 자기 자신이 만들어지지도 않았는데 어찌 .. 행동을 할수 있을까?

뭐~ 유머 코드이니 그냥 넘어가고, 그 원리만 파악하면 메모리 주소로 자신인지 검사 하는게 보일 것이다. 이게 제일 효과적이다. 하지만 효과적이라고 해서 모든 것이 완벽하진 않다.

완벽하지 않을 경우 두가지를 제시 한다.

첫째, 문자열 포인터 비교로 객체가 같은지 비교해서는 안된다. 왜냐하면 컴파일러 최적화로 인하여 두개의 다른 문자열 위치(위치로 본다면 분명 다른 위치여야 하는)가 하나의 포인터로써 가르켜질 수 있다. 아래 코드를 참조


이런 경우. 다른 객체인데도 불과하고 같은 객체로 판단 될 수 있다.

책에서의 둘째 이야기는 주제와 약간 동떨어 지므로 생략한다.

총평
매우 간단한 항목인 줄 알고(Effective 에서 지적했었기에) 대강 보려하다가, 생각도 정리할 겸 풀어서 설명하냐고 시간좀 잡아 먹었다 ^^;  대개의 경우 포인터 != 를 통하여 최적화 시킬 수 있고, 문자열 같은 상황에선 좀 조심해야 겠다.

posted by 농사를 짓는 게임 프로그래머 최익필

댓글을 달아 주세요