포인터 읽는 법: object**

트랙백: [C/C++]자주 하는 실수: http://eslife.tistory.com/324

어떤 객체를 만드는 CreateObject라는 함수를 만든다고 하자. 그런데 생성된 객체를 리턴 값을 받는 것이 아니라 인자로서 받고 싶다. 그래서 아래처럼 코딩 해버렸다.

// 잘못된 코드
bool CreateObject(object* pObj){
pObj = new object;
return (pObj != NULL);
)

C/C++ 포인터 관련해 저지르기 쉬운 실수 중 하나다. 오류는 쉽게 찾을 수 있을 것이다. object*가 아니라 object**를 넘겨 줘야 한다. 왜냐면 object*에 대한 내용을 고쳐야 하기 때문. C++ 같으면 object*&로 쓰면 되지만 보통 API는 C 인터페이스로 제공되는 것이 유리한 점이 많기 때문에 이런 경우는 많이 찾아 볼 수 있다. 대표적으로 예는 윈도우 프로그래밍에서 COM 관련 코드에서 많이 나온다. IUnknown의 QueryInterface 함수 원형은 아래와 같다. 함수 리턴 값은 통일된 반환 값으로 되어 있기 때문에 위와 같은 이중 포인터로 돌려 받고 그런다.

HRESULT QueryInterface(
REFIID iid,
void ** ppvObject
);

그런데 생각보다 적지 않은 사람들이 이런 이중, 혹은 삼중포인터에 헷갈려 하는 것 같다. 그런데 포인터를 읽을 때 아래와 같이 읽어보자. 그러면 절대 이중, 삼중, 사중, 오중 등등 포인터가 나와도 걱정 없다.

object*

object**

object***

즉, 맨 오른쪽의 *를 제외하고 왼쪽의 모든 것을 가려라. 거기에 아무리 * 기호가 더 있어도 무시해라. object**를 이중포인터 복잡하게 생각하지 말고 object*를 그냥 int 같은 하나의 타입으로 생각하면 된다. 여기에 대한 포인터일 뿐이다. 아래 같은 코드에서 int*를 int로 쓰는 실수는 거의 하지 않을 것이다.

void sum(int a, int b, int* sum){
*sum = (a+b);
}

마찬가지다. 위에서 실수한 CreateObject 코드에서도 object*를 하나의 타입으로 본다면 object*만 쓰는 실수를 범하지 않을 것이다.

bool CreateObject(object** ppObj){
*ppObj = new object;
return (*ppObj != NULL);
)

추가: C++ new 연산자는 메모리가 부족할 때 NULL을 반환하지 않고 exception을 발생합니다. MSDN에 따르면 nothrownew.obj를 명시적으로 링크하면 throw를 하지 않는다고 합니다.


by object | 2008/10/26 04:33 | 컴퓨터 | 트랙백 | 핑백(1) | 덧글(12)
트랙백 주소 : http://minjang.egloos.com/tb/2112345
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Linked at art.oriented : C.. at 2008/11/26 14:35

... close(pFile); } }그러나 나는 이 코드가 매우 “객체지향”적으로 보인다.FILE *를 “FILE 구조체에 대한 포인터”로 생각하지 말고 하나의 ‘객체’로 생각하자. 포인터 읽는 방법이라는 글에서도 썼고 불투명 타입이라는 글에서도 썼지만, 어차피 프로그래머는 FILE 구조체의 내부를 직접 조작하는 일이 없다. 표현이 포인터로 되어 있을 뿐 이건 완벽히 ... more

Commented by 엽우 at 2008/10/26 05:10
아, 전 제목만 보고 영어로 어떻게 발음하는지에 관한 내용인 줄 알았어요; ^^;;

여튼 알려주신대로 포인터를 읽어가면 훨씬 이해하기 쉽겠네요.
예전에 다른 분 코드를 보다 3중포인터때문에 헷갈렸는데 그 때도 알았다면 좋았을텐데 말이죠.
Commented by object at 2008/10/26 11:09
제목이 조금 안 맞기는하네요.
Commented by Kr015se at 2008/10/26 06:34
차라리 포인터 문법이 ptr<object> 이런 식이었으면 어떨까 하는 생각도 드네요.
하긴 어림도 없는 일이었겠지만 말이죠...
Commented by object at 2008/10/26 11:07
템플릿 기반의 오토포인터를 쓰면 비슷해지지 않을까요?
Commented by 자연풍선생 at 2008/10/26 11:41
저렇게 쓰면 된다고 알고는 있어도 막상 쓰려고 하면 항상 헷갈리는 경우가 많더군요..ㅠ.ㅠ
Commented by Lohengrin at 2008/10/26 13:09
포인터 뎁스는 되도록이면 안 깊어지는게 덜 헷갈리긴 한데, 처음 디자인한데서 늘어나다 보면 어쩔 수 없는 경우가 있으니;; 학생때는 2~4차원 포인터를 꽤 썼는데, 요즘은 되도록이면 1차원만 쓰는 구조를 선호하게 되더군요;
Commented by 몽몽이 at 2008/10/26 15:26
저런 분들에게 [C언어 포인터 완전제패]라는 책을 권하고 싶군요.
이거 본 뒤로 포인터로 헤멘 적이 없습니다.
그리고 개체 수명은 항상 caller 쪽에서 제어하게 만들면 저런 문제가 훨씬 줄어들지요.
물론, 제일 좋은 방법은 업종을 바꾸는 겁니다만.
Commented by 정섭 at 2008/10/26 20:30
제가 배웠던 방법하고 매우 유사 하네요 ^^ 저도 위와 같이 배우고 나서 이중 삼중 포인터에 대해 제대로 익힌듯 하네요.
Commented by 수아기 at 2008/10/27 19:03
정말 햇갈리더라구요. 다시 한번 적어 봐야겠습니다.^^
Commented by eslife at 2008/10/28 11:35
더 이상 쪽팔려서라도 같은 실수 안할 듯 하네요 ㅎㅎ 알려주신 방법 잘 기억해 두겠습니다.
Commented by pizon at 2008/10/28 14:57
이건 좀 다른 얘긴데, c++ 의 new 연산자는 실패했을때 NULL 을 리턴하지 않고 excepiton 을 던지는것으로 알고있습니다..
그러니깐 예제코드의 return (*ppObj != NULL); 요거는 불필요한 부분이죠.
약간 후지게(c스타일로^^) *ppObj = new(nothrow) object; 할수도 있을텐데,
요건 또 MFC 에서는 안먹힐겁니다.
Commented by object at 2008/10/28 15:26
감사합니다. 몰랐던 사실이네요. VC++ new 연산자 디폴트 구현이 NULL 반환이 아니라 exception이네요.

:         :

:

비공개 덧글

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





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 이글루스