MFC 메모리 릭 체크시 유용한 방법 2개

MFC를 사용하여 프로그램을 개발하고 있다면,


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

위의 코드를 .cpp 화일에 넣어 프로그램이 종료 되었을때 아래와 같이 누수된 메모리를 할당하는 부분의 소스 코드와 라인 수를 출력 해준다.


Detected memory leaks!
Dumping objects ->
d:\sample\sample.cpp(35) : {48} client block at 0x003739D0, subtype 0, 4 bytes long.
 Data: <(   > 28 00 00 00
d:\sample\sample.cpp(34) : {47} client block at 0x00373990, subtype 0, 4 bytes long.
 Data: <    > 1E 00 00 00
Object dump complete.

위의 예에서는 두 블록의 메모리 누수가 검출 되었는데 각 라인의 의미는

d:\sample\sample.cpp (35) : {48} client block at 0x003739D0, subtype 0, 4 bytes long.

sample.cpp 화일의 35번째 라인에서 할당된 메모리가 누수되었고 그것은 48번째로 할당된 메모리이며 메모리 주소는 0x003739d0, 4Byte가 누수되었다는 의미로 해석할 수 있다.

MFC를 사용하지 않은 프로그램의 경우 위의 DEFINE 문으로는 DEBUG_NEW를 찾을 수 없다는 컴파일 에러를 내뱉는데 그 경우엔 위의 DEFINE 문과 함께 아래와 같은 라인을 헤더에 삽입해서 해결할 수 있다.

#if !defined(_AFXDLL)
   #include <windows.h>
   #include <crtdbg.h>
   #if defined(DEBUG) | defined(_DEBUG)
      #if !defined(DEBUG_NEW)
         #define DEBUG_NEW new(_CLIENT_BLOCK, __FILE__, __LINE__)
      #endif
   #endif
#endif

DEBUG_NEW를 새로이 정의함으로써 DEBUG_NEW를 찾을 수 없는 문제를 해결한다.

간혹 malloc 을 이용한 메모리 할당은 위의 내용이 적용이 되질 않는데 이 경우엔 아래의 문장을 소스코드에 삽입한다.

- 헤더 화일에는 아래라인을 추가
#define DEBUG_MALLOC(size) _malloc_dbg(size, _NORMAL_BLOCK, __FILE__ , __LINE__)

- malloc을 재정의 하려는 소스 코드에 아래 라인을 추가.
#define malloc DEBUG_MALLOC

위의 방법들로 memory leak dump 에서 할당된 소스 코드와 라인수를  바로 찾을 수 있다.

--------------------------------------------------------------------------------------------------------------------
MFC로 프로젝트 만들어서 디버그하면 프로세스가 종료될 때 메모리 릭을 체크해서 출력창에 보여주는데, 일반 콘솔 어플리케이션이나 WIN32 어플리케이션 프로젝트로 작업하면 그런 정보를 알려주지 않아서 가끔 아쉬울 때가 있다.

그런데.. 이 '메모리 릭 검출 기능'이 MFC 프로젝트에서만 가능한 게 아니라 함수 하나만 호출해 주면 다른 프로젝트에서도 가능하다는 걸 알았다.
(이걸 이제서야 알게 되다니...OTL)

그냥 간단하게,

#include <crtdbg.h>

_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );


이렇게만 추가해 주면 된다.
(함수 호출은 main이나 WinMain함수 안에서...)


크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by shiftkey

2009/12/17 16:21 2009/12/17 16:21
, , ,
Response
No Trackback , No Comment
RSS :
http://shiftkey.org/rss/response/245

오류    1    error C2665: 'operator new' : 5개의 오버로드 중 모든 인수 형식을 변환할 수 있는 오버로드가 없습니다. 

아...뭐 짜증나게 파일하나 include 했더니 저런 에러가 뜨더라.

문제는
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static TCHAR THIS_FILE[] = _T(__FILE__);
#endif
요녀석 때문인데
이게 new를 DEBUG_NEW라는 매크로로 바뀌어서 글타는데
그래서 Release 모드에서는 괜찮다는데
짜증나서 막막 미치겠어

에러안나게 하는 방법은 저걸 주석처리하던가
저녀석 뒤에 파일을 include 해주던가 하는 방법이 있다.

p.s. 근데 여기 에서는 나와는 반대의 방법으로 해결했다고 하네 이상해 -ㅅ-
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by shiftkey

2008/12/18 08:45 2008/12/18 08:45
, ,
Response
No Trackback , No Comment
RSS :
http://shiftkey.org/rss/response/197

[MFC] 각 클래스의 포인터 얻어오기

[MFC] 각 클래스의 포인터 얻어오기

프로그램을 작성하다 보면 각 클래스들의 포인터가 필요한
경우가 있습니다. 다음과 같은 방법을 사용하면 각 클래스의
포인터를 얻을 수 있습니다.
App
   App는 전역변수로 theApp라고 선언되어 있습니다. 만약
   이를 사용하고자 한다면 Myprog.h파일의 끝부분에
   extern CMyprogApp theApp;
   라고 선언하면 프로그램의 어디서든 사용가능합니다.
   AfxGetApp()라는 함수를 사용하면 App의 포인터를
   얻을 수 있습니다.

######
dlg 에서 Doc pointer 얻는 방법

CMyprogView * pView = (CMyprogView *)(pFrame -> GetActiveView ());
CMyprogDoc *pDoc = pView -> GetDocument ();

######
GetParent () -> GetSafeHwnd ()
이것은 현재의 윈도우가 속해있는 윈도우 (다시말해서 부모 윈도우) 의 포인터를
구해서 그것의 핸들을 얻는 것입니다.


MainFrame
   MainFrame을 얻는 방법중 가장 간단한 함수는 AfxGetMainWnd입니다.
   다음과같이 사용하면 됩니다.
   CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd();

Doc
   Document를 얻는 방법은 View에서는 GetDocument입니다.
   다른 부분에서는 다음과 같이 합니다.
   CMyprogDoc *pDoc = (CMydoc*)(pFrame->GetActiveDocument());

View
   view를 얻어내는 방법은 sdi와 mdi가 약간 다릅니다.
   sdi같은 경우는 아래와 같이 간단히 되지만
   CMyView *pView = (CMyView *)(pDoc->GetActiveView());

   mdi같은 경우는 아래와 같은 복잡한 과정이 필요합니다.
   CMDIChildWnd *pChild =
             (CMDIChildWnd *) pFrame->GetActiveFrame();

   // or CMDIChildWnd *pChild = pFrame->MDIGetActive();
   CMyprogrogView *pView = (CMyprogView *) pChild->GetActiveView();
 
   MDI의 경우 한개의 도큐먼트에 뷰가 여러개 있을 때 도큐먼트에서 뷰를 찾으려면
   다음과 같이 합니다.

POSITION pos;
pos = GetFirstViewPosition();
for (;pos != NULL;)
{
CView *pView = (CView *)GetNextView(pos);
if (pView->IsKindOf(RUNTIME_CLASS(CMyView)))
break;
}





######
dlg 에서 Doc pointer 얻는 방법

// MainDialog.cpp : implementation file
//
#include "stdafx.h"
#include "Test.h"
#include "MainDlg.h"
#include "Mainfrm.h"
#include "Testdoc.h"
#include "TestView.h"

//Doc 접근
void CMainDialog::OnTestDoc()
{
//메인프레임을 통해서 CTestView 를 받는다.
CTestView* pView =
( CTestView* )((CMainFrame*)AfxGetApp()->m_pMainWnd)->GetActiveView();

//View 를 통해서 도큐먼트를 받는다.
CTestDoc *pDoc;
pDoc=pView->GetDocument();

//도큐먼트의 m_strText안에 현재 대화상자의 m_strText를 연결시킨다.
m_strText=pDoc->m_strText;
//데이타를 다이얼로그 리소스로 전송
UpdateData(FALSE);
}

//View 접근
void CMainDialog::OnTestView()
{
//메인프레임을 통해 View를 받는다.
CTestView* pView =
( CTestView* )((CMainFrame*)AfxGetApp()->m_pMainWnd)->GetActiveView();
//View안에 있는 m_strText를 현재 m_strText로 저장한다.
m_strText = pView->m_strText;
UpdateData(FALSE);
}

//MainFrame 접근
void CMainDialog::OnTestMainFrm()
{
//메인트레임에서 m_strText를 받아 현재 대화상자의 m_strText에 연결시킨다.
m_strText = ((CMainFrame*)AfxGetApp()->m_pMainWnd)->m_strText;
UpdateData(FALSE);
}


//View에서 Dialog 포인터 얻기
1.Dialog1을 호출할 View Class에서 MainDialog의 포인터 변수를 선언합니다.
//TestView.h
class CTestView : public CView
{
protected: // create from serialization only
CTestView();
DECLARE_DYNCREATE(CTestView)

// Attributes
public:
CTestDoc* GetDocument();
CString m_strText;

CMainDialog* pDlg;

}

void CTestView::OnTestDlg()
{
2.선언된 포인터 변수에 MainDialog의 포인터를 정의합니다.(메모리에 할당)
pDlg=new MainDialog;

3.Dialog Box를 띄웁니다.
pDlg->DoModal();

*1.2.3의 과정으로 Dialog1의 포인터는 구해졌습니다
}



//메뉴에서 다이얼로그 박스(MainDialog)를 하나 부릅니다..
//이 다이얼로그 박스에서 버튼을 눌러 또 다른 다이얼로그 박스를 부릅니다
//이걸 다이얼로그 SubDialog라고 하죠..
//SubDialog에서 자신을 부른 다이얼로그 박스의 변수를 억세스하기


//MainDialog에서 SubDialog를 생성했으면 SubDialog에서 View Class의 포인터를 구합니다.
//MainDialog의 포인터는 View Class에 존재하므로 SubDialog에서 View의 포인터를
//먼저구해야 합니다.
void CSubDialog::OnTestMainDialog()
{
CTestView* pView;
pView=(CTestView*)((CMainFrame*)(AfxGetApp()->m_pMainWnd))->GetActiveView();

//View Class pointer가 구해졌으면 다끝난거나 다릅없습니다.
//MainDialog의 int j의 변수에 3을입력하고 싶다면 싶다면..SubDialog에서.
(pView->pDlg)->j=3;
}


//MainDialog에서 MainFram, View, Doc 클래스를 부르려면
void CMainDialog::GetTest()
{
CMainFrame* pFrame;
pFrame = AfxGetApp()->m_pMainWnd;

CTestView* pView;
pView = pFrame->GetActiveView();

CTestDoc* pDoc;
pDoc = pView->GetDocument();
}




**참고************************************************

// BallSrvrDoc.h : interface of the CBallSrvrDoc class
//
/////////////////////////////////////////////////////////////////////////////
#include "lstnsock.h"
#include "clntsock.h"

class CBallSrvrDoc : public CDocument
{

// Attributes
public:
CListeningSocket* m_pSocket;

.......
}




BOOL CBallSrvrDoc::OnNewDocument()
{
CPortDlg Dialog;

if (Dialog.DoModal() == IDOK)
{
m_pSocket = new CListeningSocket(this); //클라이언트의 접속 요구를 기다림
}
return FALSE;
}



// lstnsock.h : header file
//
class CBallSrvrDoc;

class CListeningSocket : public CSocket
{
public:
CListeningSocket(CBallSrvrDoc* pDoc); // protected constructor used by dynamic creation
DECLARE_DYNAMIC(CListeningSocket);
// Attributes
public:
CBallSrvrDoc* m_pDoc;
// Operations
public:

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CListeningSocket)
//}}AFX_VIRTUAL

// Implementation
public:
virtual ~CListeningSocket();
virtual void OnAccept(int nErrorCode);
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif

// Generated message map functions
protected:
};
#endif


// lstnsock.cpp : implementation file
//

#include "stdafx.h"
#include "ballsrvr.h"
#include "lstnsock.h"
#include "srvrdoc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CListeningSocket

CListeningSocket::CListeningSocket(CBallSrvrDoc* pDoc)
{
m_pDoc = pDoc;
}

/////////////////////////////////////////////////////////////////////////////
// CListeningSocket Overridable callbacks

void CListeningSocket::OnAccept(int nErrorCode)
{
CSocket::OnAccept(nErrorCode);
m_pDoc->ProcessPendingAccept();
}


다이얼로그의 핸들이란 곧 윈도우의 핸들이죠.
CWnd에서 상속받아 만들어진 모든 것들은 다 윈도우입니다.
그렇기 때문에 CWnd에 있는 m_hWnd를 갖고 있죠.
다이얼로그도 마찬가지로 하나의 윈도우이기 때문에 m_hWnd를 갖고 있습니다.
따라서 다이얼로그의 m_hWnd를 사용하시면 됩니다.
예)   CTestDlg dlg;
      HWND hDialog = dlg.m_hWnd;


원문링크 : [MFC] 각 클래스의 포인터 얻어오기
크리에이티브 커먼즈 라이센스
Creative Commons License

Posted by shiftkey

2008/03/05 01:56 2008/03/05 01:56
, , ,
Response
No Trackback , No Comment
RSS :
http://shiftkey.org/rss/response/125


블로그 이미지

Shiftkey가 살아가는 이런 저런 이야기......

- shiftkey

Notices

Archives

Authors

  1. shiftkey

Calendar

«   2012/02   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29      

Site Stats

Total hits:
135404
Today:
140
Yesterday:
312