|
2009년 01월 22일
ASSERT_VALID 매크로는 객체의 메모리 영역과 멤버변수에 대한 유효성을 검사하는데 사용되는 매크로 함수 입니다. 이 매크로 함수를 이용하기 위해서는 클래스를 정의 할 때 반드시 CRuntimeClass를 선언 및 구현해 주어야하며, CObject를 상속 받아야 합니다. 이렇게 해주는 이유는 ASSERT_VALID 매크로 함수는 내부적으로 ::AfxAssertValidObject(pOb, THIS_FILE, __LINE__) 함수를 호출하는데, 이 함수 내부에서 CRuntimeClass의 m_nObjectSize 멤버 변수를 이용해 메모리 주소 공간이 옳바른지 체크하는 루틴이 존재하기 때문이며, CObject의 멤버 가상 함수인 AssertValid를 호출하여 객체의 멤버변수에 대한 유효성 검사를 수행하기 때문입니다. #define ASSERT_VALID(pOb) (::AfxAssertValidObject(pOb, THIS_FILE, __LINE__)) 아래는 AfxAssertValidObject 함수의 정의입니다. 우선 보이는 것이 #ifdef _DEBUG 인데, 보시는 봐와 같이 이 함수는 컴파일러가 디버그 모드일 때만 정의 되도록 되어 있습니다. 결국, 릴리즈 모드로 빌드해서 배포할때는 이 함수는 포함되지 않기 때문에 코드의 양이 많이지는 부담이 전혀 없습니다. 그렇기 때문에 효율적으로 객체를 관리하기 위해서 객체의 메모리와 멤버 변수들이 유효한지 확인하고 싶을때 여기저기 많이 사용한다면 디버깅 할 때 굉장히 유리할 뿐만 아니라 좀 더 견고하고 완성도 높은 프로그램을 개발하는데 많은 도움이 되리라 생각됩니다. 아래 함수의 동작은 인자로 들어 온 pOb에 대한 NULL 검사를 수행한 이후, CObject 클래스의 크기 만큼 메모리 블록이 유효한지 검사를 합니다. 다음으로 객체의 메모리 블록 최초 4byte를 검사하여 virtual table이 유효한지 검사하며 CRuntimeClass의 m_nObjectSize 멤버 변수를 이용하여 객체의 모든 메모리 영역이 유효한지 검사합니다. 마지막으로 AssertValid함수를 호출하여 객체의 멤버 변수에 대한 유효성 검사를 수행합니다. #ifdef _DEBUG void AFXAPI AfxAssertValidObject(const CObject* pOb, LPCSTR lpszFileName, int nLine) { if (pOb == NULL) { TRACE(traceAppMsg, 0, "ASSERT_VALID fails with NULL pointer.\n"); if (AfxAssertFailedLine(lpszFileName, nLine)) AfxDebugBreak(); return; // quick escape } if (!AfxIsValidAddress(pOb, sizeof(CObject))) { TRACE(traceAppMsg, 0, "ASSERT_VALID fails with illegal pointer.\n"); if (AfxAssertFailedLine(lpszFileName, nLine)) AfxDebugBreak(); return; // quick escape } // check to make sure the VTable pointer is valid if (!AfxIsValidAddress(pOb, pOb->GetRuntimeClass()->m_nObjectSize, FALSE)) 그럼, 위에서 처럼 AssertValid() 함수만 호출 되면 객체의 멤버변수가 유효한지 자동으로 검사를 해 줄까요? 전혀 그렇지 않습니다. 아래는 CObject 클래스의 AssertValid 함수의 선언과 정의입니다. 보시는 봐와 같이 AssertValid 함수는 virtual로 선언 되어있습니다. 이는 다형성을 이용하여 CObject로 부터 파생되는 클래스가 AssertValid 함수를 재정의 하도록 하여 객체 멤버변수에 대한 유효성 검사를 수행하도록 한 함수입니다. CObject로 부터 파생된 클래스는 자신의 부모 클래스의 AssertValid를 호출 한 후 자신의 멤버변수에 대한 유효성 검사를 수행하면 됩니다. CObject클래스의 AssertValid 함수의 정의를 보면 자기 자신의 객체에 대한 NULL 검사를 수행하고 있는 것을 확인하실 수 있습니다. #if defined(_DEBUG) || defined(_AFXDLL) // Diagnostic Support virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif void CObject::AssertValid() const { ASSERT(this != NULL); } 위 설명을 기초로 하여 간단히 ASSERT_VALID 매크로를 사용하는 예제 코드를 만들어 보았습니다. // ASSERT_VALID.cpp : Defines the entry point for the console application. // #include "stdafx.h" class Base : public CObject { // // CRuntimeClass를 선언합니다. // DECLARE_DYNAMIC(Base) int i; public: Base(int i) { this->i = i; } virtual ~Base() {} #ifdef _DEBUG virtual void AssertValid() const { // // 자신의 상위 클래스의 AssertValid함수를 호출하여 // 상위 클래스의 멤버 변수에 대한 유효성 검사를 수행합니다. // CObject::AssertValid(); ASSERT(i > 0); } #endif }; // // CRuntimeClass를 정의합니다. // IMPLEMENT_DYNAMIC(Base, CObject) class Derived : public Base { // // CRuntimeClass를 선언합니다. // DECLARE_DYNAMIC(Derived) int j; public: Derived(int i, int j) : Base(i) { this->j = j; } virtual ~Derived() {}; #ifdef _DEBUG virtual void AssertValid() const { // // 자신의 상위 클래스의 AssertValid함수를 호출하여 // 상위 클래스의 멤버 변수에 대한 유효성 검사를 수행합니다. // Base::AssertValid(); ASSERT(j > 0); } #endif }; // // CRuntimeClass를 정의합니다. // IMPLEMENT_DYNAMIC(Derived, Base) int _tmain(int argc, _TCHAR* argv[]) { Base* p = new Derived(-1, -1); ASSERT_VALID(p); delete p; return 0; } * 실행 결과 위 예제 코드를 보시면 각 클래스의 멤버 변수는 0보다 큰 값을 가져야 함을 알 수 있습니다. 하지만 생성자에서는 -1을 각각 멤버 변수에 할당해 두었습니다. 결국 프로그램을 실행하면 아래와 같이 ASSERT 창이 뜨며 문제가 발생한 파일 명과 라인 넘버를 출력해 줍니다. 물론 Debug 모드에서 실행을 하셔야합니다 ~ ^^ ![]()
|
ABOUT
![]() 새로운 도전을 위해 약 1년간 자리를 비웁니다. 그 동안 블로그에 방문해 주신 분들께 진심으로 감사드립니다. 1년 뒤 .NET 관련 양질의 정보를 가지고 돌아오겠습니다. by greenfrog 메모장
카테고리
최근 등록된 덧글
잘 봤습니다. 그런데 저 상태에서 하얀..
by 비니 at 07/24 안녕하세요. 내용이 좋아서 참고합니다... by 김현수 at 07/09 1년뒤....너무 멀군요... 도전 성.. by rince at 06/26 좋은 내용이네요 많은 도움이 되었습니다.. by 이준배 at 06/04 좋은 정보 감사합니다^^ by 코즈 at 06/03 사랑합니다 by 최곱니다 at 05/12 좋은정보 감사합니다. by 이창열 at 05/11 좋은 정보 잘보고갑니다 그리고 제가 .. by Cherry at 04/27 답글이 늦어서 죄송합니다. 요즘 이래저.. by greenfrog at 04/20 좋은 정보 잘보고 갑니다^^ 도움이 많.. by 토끼 at 04/15 좋은 정보 감사합니다. 다음에 써먹어야.. by neptunex at 03/26 ㅎㅎ 잘 찾아보면 재미있는 플러그인 많.. by greenfrog at 03/22 예전에는 일부러 에러내고 그거찾아가는.. by 규학 at 03/13 아 ~ 그 일이었군요 ^^ 글 잘 봤어요 .. by greenfrog at 02/21 하나은행과 정말 생동감 넘쳤지요 ^^ by rince at 02/20 rince님의 생동감 넘치는 하루가 궁금.. by greenfrog at 02/20 어제, 그제 정말 생동감 넘치는 하루.. by rince at 02/19 저도 짬 비릴때 고참들이 웃기면 그것 .. by greenfrog at 02/19 전 자주 웃는 편이지요 ^^; 군대에선 .. by rince at 02/18 저도 이 만화 보고 어쩜 저런 생각 없는 .. by greenfrog at 02/17 최근 등록된 트랙백
자바로 작성된 프로그램 단 한번만 실..
by Start!!! 제 취향이 Oddly Enough와 안성맞.. by Oddly Enough 2009년 보기 시작하는 미드 by Pell's seer Blog [포토] 국민 여러분, 떡국 드시고 .. by Green Monkey Blog** MARVEL MOVIES : 아이언 맨 by 잠보니스틱스 ▶◀ 최진실씨, 삼가 고인의 명복을 .. by ** MY's kitchen ** 재미로 해보는 MBTI 검사 by A2공간 - 도움되는 글을 쓰자 러시아 극우조직 스킨헤드를 파헤친 기자 by Oddly Enough [Sleeping Through My Fingers].. by 바람나무, 생각가는대로 구글 크롬 안내서의 작지만 큰 실수 by Oddly Enough PETA, 돼지학대 농장 잠입취재 by Oddly Enough 병쭈니의 생각 by chrisjun82's me2DAY 준이아빠의 생각 by kkh1030's me2DAY 안철수가 말하는 "현대의 인재에.. by loading... 100% 이전블로그
이글루 파인더
|