1. Introduction

Download Report

Transcript 1. Introduction

Chapter
04
MFC Utility Class
Contents
Simple value types
– 일반적 목적 : CString, CTime, CTimeSpan
– 윈도우 구조체 : CPoint, CSize, Crect
MFC collection classes
– array, linked list, map
CFile class family
CException class
[1]
비트교육센터
Introduction
우리가 만드는 많은 class들
– Utility class의 범주에 든다.
– 이 단원의 목적
MFC 개발자 들의 technique
앞으로의 project에 도움
[2]
비트교육센터
Simple Value Types
Simple value types
– C++ type(char*, …), Windows type(RECT, …) 들을 encapsulating 한 클래
스들
– C++ interface 제공
– 더 안전하고 더 쉽게 이용할 수 있는 operator 제공
memory management
internationalization
…
[3]
비트교육센터
Class CString
Character string을 encapsulate함
다음과 같은 특징이 있음
–
–
–
–
–
–
Internationalization
Memory allocation/deallocation
Operators(+, =, ==, …)
String searching
String manipulation(reverse, concat)
Formatting(printf-like)
[4]
비트교육센터
Using a CString
생성
// create a CString from a char *
CString myString1(“This is a string”);
// create a CString from a CString
CString myString2(myString1);
// create a CString with 80 z characters
CString myString3(‘z’, 80);
// create a CString as empty CString
CString myString4;
[5]
비트교육센터
Using a CString (cont’d)
CString myString1(“string 1”);
CString myString2(“string 2”);
CString myString3(“string 3”);
// addition (concatenation) & assignment
myString1 += myStrig2;
myString3 = “This is “ + myString2;
myString2 += ‘Z’;
// comparison : == , < , != , …
if ( myString1 == myString2 ) // like strcmp
// operator[] : 0-based
if ( myString1[7] == ‘l’ )
// find : Find(), FindOneOf(), ReverseFind()
[6]
비트교육센터
CString Internals
CString declaration(AFX.H)
class CString
{
public:
// Constructors
CString();
CString(const CString& stringSrc);
CString(TCHAR ch, int nRepeat = 1);
CString(LPCSTR lpsz);
CString(LPCWSTR lpsz);
CString(LPCSTR lpch, int nLength);
CString(LPCWSTR lpch, int nLength);
CString(const unsigned char* psz);
[7]
비트교육센터
CString Internals (cont’d)
// Attributes & Operations
int GetLength() const;
BOOL IsEmpty() const;
void Empty();
TCHAR GetAt(int nIndex) const;
TCHAR operator[](int nIndex) const;
void SetAt(int nIndex, TCHAR ch);
operator LPCTSTR() const;
const CString& operator=(const CString& stringSrc);
const CString& operator=(TCHAR ch);
const CString& operator=(LPCSTR lpsz);
const CString& operator=(LPCWSTR lpsz);
const CString& operator=(const unsigned char* psz);
[8]
비트교육센터
CString Internals (cont’d)
// concatenate
const CString& operator+=(const CString& string);
const CString& operator+=(TCHAR ch);
const CString& operator+=(LPCTSTR lpsz);
friend CString AFXAPI operator+(const CString& string1,
const CString& string2);
friend CString AFXAPI operator+(const CString& string, TCHAR ch);
friend CString AFXAPI operator+(TCHAR ch, const CString& string);
friend CString AFXAPI operator+(const CString& string, LPCTSTR lpsz);
friend CString AFXAPI operator+(LPCTSTR lpsz, const CString& string);
// string comparison
int Compare(LPCTSTR lpsz) const;
int CompareNoCase(LPCTSTR lpsz) const;
int Collate(LPCTSTR lpsz) const;
int CollateNoCase(LPCTSTR lpsz) const;
[9]
비트교육센터
CString Internals (cont’d)
// simple sub-string extraction
CString Mid(int nFirst, int nCount) const;
CString Mid(int nFirst) const;
CString Left(int nCount) const;
CString Right(int nCount) const;
CString SpanIncluding(LPCTSTR lpszCharSet) const;
CString SpanExcluding(LPCTSTR lpszCharSet) const;
// upper/lower/reverse conversion
void MakeUpper();
void MakeLower();
void MakeReverse();
// advanced manipulation
int Replace(TCHAR chOld, TCHAR chNew);
int Replace(LPCTSTR lpszOld, LPCTSTR lpszNew);
int Remove(TCHAR chRemove);
int Insert(int nIndex, TCHAR ch);
int Insert(int nIndex, LPCTSTR pstr);
int Delete(int nIndex, int nCount = 1);
[10]
비트교육센터
CString Internals (cont’d)
// searching
int Find(TCHAR ch) const;
int ReverseFind(TCHAR ch) const;
int Find(TCHAR ch, int nStart) const;
int FindOneOf(LPCTSTR lpszCharSet) const;
int Find(LPCTSTR lpszSub) const;
int Find(LPCTSTR lpszSub, int nStart) const;
// simple formatting
void AFX_CDECL Format(LPCTSTR lpszFormat, ...);
void AFX_CDECL Format(UINT nFormatID, ...);
void FormatV(LPCTSTR lpszFormat, va_list argList);
// input and output
friend CArchive& AFXAPI operator<<(CArchive& ar, const CString& string);
friend CArchive& AFXAPI operator>>(CArchive& ar, CString& string);
// load from string resource
BOOL LoadString(UINT nID);
[11]
비트교육센터
CString Internals (cont’d)
// get pointer to modifiable buffer at least as long as nMinBufLength
LPTSTR GetBuffer(int nMinBufLength);
// release buffer, setting length to nNewLength (or to first nul if -1)
void ReleaseBuffer(int nNewLength = -1);
// get pointer to modifiable buffer exactly as long as nNewLength
LPTSTR GetBufferSetLength(int nNewLength);
// release memory allocated to but unused by string
void FreeExtra();
// turn refcounting back on
LPTSTR LockBuffer();
// turn refcounting off
void UnlockBuffer();
// Implementation
public:
~CString();
int GetAllocLength() const;
[12]
비트교육센터
CString Internals (cont’d)
protected:
LPTSTR m_pchData; // pointer to ref counted string data
// implementation helpers
CStringData* GetData() const;
void Init();
void AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
int nExtraLen) const;
void AllocBuffer(int nLen);
void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);
void ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
int nSrc2Len, LPCTSTR lpszSrc2Data);
void ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData);
void CopyBeforeWrite();
void AllocBeforeWrite(int nLen);
static void PASCAL Release(CStringData* pData);
static int PASCAL SafeStrlen(LPCTSTR lpsz);
static void FASTCALL FreeData(CStringData* pData);
};
[13]
비트교육센터
CString Internals (cont’d)
CString declaration(AFX.H)
– m_pchData
유일한 멤버 변수
String에 대한 pointer
– CStringData
CString의 기능 구현을 도와주는 structure
struct CStringData
{
long nRefs;
// reference count
int nDataLength;
// length of data (including terminator)
int nAllocLength;
// length of allocation
TCHAR* data()
// TCHAR* to managed data
{ return (TCHAR*)(this+1); }
};
[14]
비트교육센터
CString Internals (cont’d)
– 공간 할당 함수 AllocBuffer()(STRCORE.CPP)
void CString::AllocBuffer(int nLen)
{
if (nLen == 0)
Init();
else
{
CStringData* pData =
(CStringData*)newBYTE[sizeof(CStringData) +
(nLen+1)*sizeof(TCHAR)];
pData->nAllocLength = nLen;
pData->nRefs = 1;
pData->data()[nLen] = '\0';
pData->nDataLength = nLen;
m_pchData = pData->data();
}
}
[15]
비트교육센터
CString Internals (cont’d)
– AllocBuffer()함수에 의한 memory 할당
CStringData
nRefs
nDataLength
Data(nlength + 1)
nAllocLength
CString::m_pchData
[16]
비트교육센터
CString Internals (cont’d)
– 의문점
CString class는 string 이외의 데이터를 숨김
왜, 그들을 멤버변수로 추가하지 않았는가
CString object와 TCHAR *은 똑같아야 한다.
– same bits
그 이외의 부가적인 정보는 CStringData 에서 관리
이전 버전과의 호환성
[17]
비트교육센터
CString Internals (cont’d)
– Reference counting
CStringData::nRefs
실제 데이터의 변경이 가해지면 copy
CString myString1(“This is a string”);
CString myString2(myString1);
CString myString3 = myString1;
myString2
myString1
“This is a string”
myString3
[18]
비트교육센터
CString Internals (cont’d)
– Reference counting 과정
nRefs 변수의 값이 -1 으로 초기화
그 string에 새 참조가 발생하면 1 증가
참조가 줄어들면 1 감소
다시 0이 되면 삭제 가능
참조되는 string에 쓰기가 발생하면 새로운 string을 생성하고 원래의
string의 nRefs값을 1 감소
– Critical resource
일종의 OS에서 발생하는 resource 공유 문제
두 thread 에서 동시에 참조를 증가 혹은 감소시키는 경우 문제 해결
– InterlockedIncrement(), InterlockedDecrement()
[19]
비트교육센터
CString Internals (cont’d)
예제
Line 1
Line 2
Line 3
Line 4
Line 5
CString myString1(“This is my string1”);
CString myString2(myString1);
CString myString3; myString3 = myString2;
// Write somthing
myString3.MakeUpper();
[20]
비트교육센터
CString Internals (cont’d)
“Strcore.cpp”
CString::CString(LPCTSTR lpsz)
{
int nLen = SafeStrlen(lpsz);
if (nLen != 0)
{
AllocBuffer(nLen);
memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
}
}
1
myString1
“This is my string1”
[21]
비트교육센터
CString Internals (cont’d)
CString::CString(const CString& stringSrc)
{
if (stringSrc.GetData()->nRefs >= 0)
{
m_pchData = stringSrc.m_pchData;
InterlockedIncrement(&GetData()->nRefs);
} else {
Init();
*this = stringSrc.m_pchData;
}
}
2
myString1
“This is my string1”
[22]
myString2
비트교육센터
CString Internals (cont’d)
const CString& CString::operator= (const CString& stringSrc)
{
if (m_pchData != stringSrc.m_pchData) {
if ((GetData()->nRefs < 0 && GetData() != _afxDataNil) ||
stringSrc.GetData()->nRefs < 0) {
// actual copy necessary since one of the strings is locked
AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
} else {
// can just copy references around
Release();
m_pchData = stringSrc.m_pchData;
InterlockedIncrement(&GetData()->nRefs);
}
}
return *this;
}
3
myString1
“This is my string1”
[23]
myString2
myString3
비트교육센터
CString Internals (cont’d)
void CString::MakeUpper()
{
CopyBeforeWrite();
_tcsupr(m_pchData);
}
void CString::CopyBeforeWrite()
{
if (GetData()->nRefs > 1)
{
CStringData* pData = GetData();
Release();
AllocBuffer(pData->nDataLength);
memcpy(m_pchData,pData->data(),
(pData->nDataLength+1)*sizeof (TCHAR));
}
ASSERT(GetData()->nRefs <= 1);
}
[24]
비트교육센터
CString Internals (cont’d)
void CString::Release()
{
if (GetData() != _afxDataNil)
{
ASSERT(GetData()->nRefs != 0);
if (InterlockedDecrement(&GetData()->nRefs) <= 0)
FreeData(GetData());
Init();
}
}
2
myString1
“This is my string1”
1
myString3
“THIS IS MY STRING1”
[25]
myString2
비트교육센터
CString Internals (cont’d)
Internationalization
– _t internationalized string 함수를 이용하여 구현
_tcschr() => strchr() mapping
int CString::Find(TCHAR ch, int nStart) const
{
int nLength = GetData()->nDataLength;
if (nStart >= nLength)
return -1;
LPTSTR lpsz = _tcschr(m_pchData + nStart, (_TUCHAR)ch);
return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
}
[26]
비트교육센터
Other Simple Value Types
Value Type
Structure
Source File
CPoint
POINT(struct tagPOINT)
afxwin1.inl
CRect
RECT(struct tagRECT)
afxwin1.inl, wingdix.cpp
CSize
SIZE(struct tagSIZE)
afxwin1.inl
CTime
time_t operations
afx.inl, timecore.cpp
CTimeSpan
time_t math
afx.inl, timecore.cpp
[27]
비트교육센터
Class CRect
Declaration (AFXWIN.H)
class CRect : public tagRECT
{
…
typedef struct tagRECT
{
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;
[28]
비트교육센터
Class CRect (cont’d)
void CRect::DeflateRect(LPCRECT lpRect)
{
left += lpRect->left;
top += lpRect->top;
right -= lpRect->right;
bottom -= lpRect->bottom;
}
[29]
비트교육센터
MFC Collection Classes
MFC collection classes
– Array
일반적인 C++에서의 array임
단 모든 메모리관련 기능 추가
– List
Doubly linked list
– Map
일종의 dictionary
Key, value 쌍으로 데이터를 저장
[30]
비트교육센터
Type of Collection Classes
Template-based
Collection contents
Array
List
Map
Collections of objects of
any type
CArray
CList
Cmap
Collections of pointers to
to objects of any type
CTypedPtrArray
CTypedPtrList
CTypedPtrMap
Nontemplate-based
– Array : CObArray, CByteArray, …
– List : CObList, CPtrList, CStringList
– Map : CMapPtrToWord, …
[31]
비트교육센터
Shape Features
Shape
Ordered?
Indexed?
Insert
Search
Duplicate
List
Yes
No
Fast
Slow
Yes
Array
Yes
By int
Slow
Slow
Yes
Map
No
By key
Fast
Fast
No(key)
Yes(value)
[32]
비트교육센터
Type-safe Collection
Template-based classes
– 변수 선언
– 멤버 함수 호출
– 필요할 경우, helper function 구현 (CArray, CList, CMap 에서)
CompareElements
CopyElements
Dumpelements
HashKey
SerializeElements
[33]
비트교육센터
Type-safe Collection (cont’d)
// 변수 선언
CList<int, int> m_intList;
// 함수 호출
m_intList.AddTail( 100 );
m_intList.RemoveAll( );
// helper function 구현
class CPerson : public CObject { . . . };
CArray< CPerson, CPerson& > personArray;
template <> void AFXAPI SerializeElements <CPerson> ( CArchive& ar,
CPerson* pNewPersons, int nCount )
{
for ( int i = 0; i < nCount; i++, pNewPersons++ )
{
// Serialize each CPerson object
pNewPersons->Serialize( ar );
}
}
[34]
비트교육센터
Type-safe Collection (cont’d)
Nontemplate-based classes
– 방법 1 : Type-casting 활용
– 방법 2 : 파생클래스 생성
class CPerson : public CObject {...};
CPerson* p1 = new CPerson(...);
CObList myList;
myList.AddHead( p1 ); // No cast needed
CPerson* p2 = ( CPerson* )myList.GetHead();
class CPersonList : public CObList
{
public:
void AddHeadPerson( CPerson* person ) {AddHead( person );}
const CPerson* GetHeadPerson() {return (CPerson*)GetHead();}
};
[35]
비트교육센터
Iteration
Array
CTypedPtrArray<CObArray, CPerson*> myArray;
for( int i = 0; i < myArray.GetSize();i++ ){
CPerson* thePerson = myArray.GetAt( i );
// CPerson* thePerson = myArray[ i ];
}
List
CTypedPtrList<CObList, CPerson*> myList;
POSITION pos = myList.GetHeadPosition();
while( pos != NULL )
{
CPerson* thePerson = myList.GetNext( pos );
...
}
[36]
비트교육센터
Iteration (cont’d)
Map
CMap<CString, LPCTSTR, CPerson*, CPerson*> myMap;
POSITION pos = myMap.GetStartPosition();
while( pos != NULL ) {
CPerson* pPerson;
CString string;
myMap.GetNextAssoc( pos, string, pPerson );
}
CMapStringToOb myMap; // A nontemplate collection class
POSITION pos = myMap.GetStartPosition( );
while( pos != NULL ) {
CPerson* pPerson;
CString string;
myMap.GetNextAssoc( pos, string, (CObject*&)pPerson );
ASSERT( pPerson->IsKindOf( RUNTIME_CLASS( CPerson ) ) );
}
[37]
비트교육센터
Additional Structures
Stack
class CTray : public CObject { ... };
class CStack : public CTypedPtrList< CObList, CTray* >
{
public:
// Add element to top of stack
void Push( CTray* newTray )
{ AddHead( newTray ); }
// Peek at top element of stack
CTray* Peek()
{ return IsEmpty() ? NULL : GetHead(); }
// Pop top element off stack
CTray* Pop()
{ return RemoveHead(); }
};
[38]
비트교육센터
Additional Structures (cont’d)
Queue
class CPerson : public CObject { ... };
class CQueue : public CTypedPtrList< CObList, CPerson* >
{
public:
// Go to the end of the line
void AddToEnd( CPerson* newPerson )
{ AddTail( newPerson ); }
// End of the queue
// Get first element in line
CPerson* GetFromFront()
{ return IsEmpty() ? NULL : RemoveHead(); }
};
[39]
비트교육센터
Array Collections
Array collections
–
–
–
–
CByteArray, CDWordArray, CUintArray
CObArray, CStringArray, CWordArray
AFXCOLL.H
ARRAY_X.CPP ( X : type of array )
void ArrayExample()
{
CUintArray myIntArray;
myIntArray.SetSize(100);
for ( int I=0; I<100; I++ )
myIntArray.SetAt(I, 2*I);
UINT bogus = myIntArray[50];
bogus = myIntArray.GetAt(50);
myIntArray.DeleteAt(50);
}
[40]
비트교육센터
CWordArray Class
class CWordArray : public CObject
{
DECLARE_SERIAL(CWordArray)
public:
// Attributes
int GetSize() const;
int GetUpperBound() const;
void SetSize(int nNewSize, int nGrowBy = -1);
// Operations
void FreeExtra();
void RemoveAll();
WORD GetAt(int nIndex) const;
void SetAt(int nIndex, WORD newElement);
WORD& ElementAt(int nIndex);
[41]
비트교육센터
CWordArray Class (cont’d)
// Direct Access to the element data (may return NULL)
const WORD* GetData() const;
WORD* GetData();
// Potentially growing the array
void SetAtGrow(int nIndex, WORD newElement);
int Add(WORD newElement);
int Append(const CWordArray& src);
void Copy(const CWordArray& src);
// overloaded operator helpers
WORD operator[](int nIndex) const;
WORD& operator[](int nIndex);
// Operations that move elements around
void InsertAt(int nIndex, WORD newElement, int nCount = 1);
void RemoveAt(int nIndex, int nCount = 1);
void InsertAt(int nStartIndex, CWordArray* pNewArray);
[42]
비트교육센터
CWordArray Class (cont’d)
// Implementation
protected:
WORD* m_pData; // the actual array of data
int m_nSize;
// # of elements (upperBound - 1)
int m_nMaxSize; // max allocated
int m_nGrowBy; // grow amount
public:
~CWordArray();
void Serialize(CArchive&);
#ifdef _DEBUG
void Dump(CDumpContext&) const;
void AssertValid() const;
#endif
protected:
// local typedefs for class templates
typedef WORD BASE_TYPE;
typedef WORD BASE_ARG_TYPE;
};
[43]
비트교육센터
CWordArray Class (cont’d)
CWordArray(ARRAY_W.CPP)
– 멤버 변수
m_pData
– 저장된 데이터의 포인터
m_nSize
– Current size of array(“logical” size)
m_nMaxSize
– “Physical” size
M_nGrowBy
– 추가 메모리 할당시 추가 할당 크기
SetSize()를 통한 이해
[44]
비트교육센터
CWordArray Class (cont’d)
void CWordArray::SetSize(int nNewSize, int nGrowBy)
{
if (nGrowBy != -1) m_nGrowBy = nGrowBy; // set new size
if (nNewSize == 0)
{
// shrink to nothing
delete[] (BYTE*)m_pData;
m_pData = NULL;
m_nSize = m_nMaxSize = 0;
}
else if (m_pData == NULL)
{
// create one with exact size
m_pData = (WORD*) new BYTE[nNewSize * sizeof(WORD)];
memset(m_pData, 0, nNewSize * sizeof(WORD)); // zero fill
m_nSize = m_nMaxSize = nNewSize;
}
[45]
비트교육센터
CWordArray Class (cont’d)
else if (nNewSize <= m_nMaxSize) {
// it fits
if (nNewSize > m_nSize) {
// initialize the new elements
memset(&m_pData[m_nSize],
0, (nNewSize-m_nSize) * sizeof(WORD));
}
m_nSize = nNewSize;
} else {
// otherwise, grow array
int nGrowBy = m_nGrowBy;
if (nGrowBy == 0)
nGrowBy = min(1024, max(4, m_nSize / 8));
int nNewMax;
if (nNewSize < m_nMaxSize + nGrowBy)
nNewMax = m_nMaxSize + nGrowBy; // granularity
else
nNewMax = nNewSize; // no slush
WORD* pNewData = (WORD*) new BYTE[nNewMax * sizeof(WORD)];
비트교육센터
[46]
CWordArray Class (cont’d)
// copy new data from old
memcpy(pNewData, m_pData, m_nSize * sizeof(WORD));
memset(&pNewData[m_nSize], 0, (nNewSize-m_nSize)*sizeof(WORD));
// get rid of old stuff (note: no destructors called)
delete[] (BYTE*)m_pData;
m_pData = pNewData;
m_nSize = nNewSize;
m_nMaxSize = nNewMax;
}
}
[47]
비트교육센터
CWordArray Class (cont’d)
SetSize()(ARRAY_W.CPP)
– 5개의 section으로 구성
Initialization section
Shrink-to-nothing section
First allocation section
Allocate-from-extra-space section
Grow-the-array section
[48]
비트교육센터
CWordArray Class (cont’d)
SetAt()(AFXCOLL.INL)
– m_pData[nIndex] = newElement;
InsertAt()(ARRAY_W.CPP)
– Array마지막에 insert하는 경우
메모리 할당 후 insert
– Array 중간에 insert하는 경우
메모리 할당 후 데이터 이동작업
Expensive  무분별한 사용을 삼가
[49]
비트교육센터
CWordArray Class (cont’d)
void CWordArray::InsertAt(int nIndex, WORD newElement, int nCount)
{
if (nIndex >= m_nSize) // adding after the end of the array
SetSize(nIndex + nCount); // grow so nIndex is valid
else { // inserting in the middle of the array
int nOldSize = m_nSize;
SetSize(m_nSize + nCount); // grow it to new size
// shift old data up to fill gap
memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
(nOldSize-nIndex) * sizeof(WORD));
// re-init slots we copied from
memset(&m_pData[nIndex], 0, nCount * sizeof(WORD));
}
// insert new value in the gap
while (nCount--) m_pData[nIndex++] = newElement;
}
[50]
비트교육센터
CWordArray Class (cont’d)
GetAt() and operator[] (AFXCOLL.INL)
– 많은 데이터 access함수가 GetAt()을 내부적으로 호출
내부 구현 변경시 GetAt()만 수정하면 됨
Data abstraction 기술을 배울만함
_AFXCOLL_INLINE WORD CWordArray::GetAt(int nIndex) const
{ ASSERT(nIndex >= 0 && nIndex < m_nSize);
return m_pData[nIndex]; }
_AFXCOLL_INLINE WORD CWordArray::operator[](int nIndex) const
{ return GetAt(nIndex); }
[51]
비트교육센터
List Collections
List collections
– CObList, CPtrList, CStringList
– Doubly linked list
– Supporting operator as follows
AddHead(), Find(), GetCount()
GetHEad(), GetNext(), GetTail(), IsEmpty()
RemoveAll(), RemoveHead(), RemoveTail()
InsertAfter(), InsertBefore()
POSITION pos = m_strList.GetHeadPositon();
while ( pos != NULL )
CString tmpString = m_strList.GetNext(pos);
[52]
비트교육센터
CStringList Class
class CStringList : public CObject
{
DECLARE_SERIAL(CStringList)
protected:
struct CNode
{
CNode* pNext;
CNode* pPrev;
CString data;
};
public:
// Construction
CStringList(int nBlockSize = 10);
// Attributes (head and tail)
int GetCount() const;
BOOL IsEmpty() const;
// peek at head or tail
CString& GetHead();
[53]
비트교육센터
CStringList Class (cont’d)
// Operations
CString RemoveHead();
CString RemoveTail();
POSITION AddHead(LPCTSTR newElement);
POSITION AddTail(LPCTSTR newElement);
POSITION AddHead(const CString& newElement);
POSITION AddTail(const CString& newElement);
void AddHead(CStringList* pNewList);
void AddTail(CStringList* pNewList);
void RemoveAll();
POSITION GetHeadPosition() const;
POSITION GetTailPosition() const;
CString& GetNext(POSITION& rPosition); // return *Position++
CString GetNext(POSITION& rPosition) const; // return *Position++
CString& GetPrev(POSITION& rPosition); // return *Position-CString GetPrev(POSITION& rPosition) const; // return *Position-CString& GetAt(POSITION position);
CString GetAt(POSITION position) const;
void SetAt(POSITION pos, LPCTSTR newElement);
void SetAt(POSITION pos, const CString& newElement);
void RemoveAt(POSITION position);
[54]
비트교육센터
CStringList Class (cont’d)
POSITION
POSITION
POSITION
POSITION
POSITION
POSITION
InsertBefore(POSITION position, LPCTSTR newElement);
InsertAfter(POSITION position, LPCTSTR newElement);
InsertBefore(POSITION position, const CString& newElement);
InsertAfter(POSITION position, const CString& newElement);
Find(LPCTSTR searchValue, POSITION startAfter = NULL) const;
FindIndex(int nIndex) const;
// Implementation
protected:
CNode*
m_pNodeHead;
CNode*
m_pNodeTail;
int
m_nCount;
CNode*
m_pNodeFree;
struct CPlex*
m_pBlocks;
int m_nBlockSize;
CNode* NewNode(CNode*, CNode*);
void FreeNode(CNode*);
typedef CString BASE_TYPE;
typedef LPCTSTR BASE_ARG_TYPE;
};
[55]
비트교육센터
CStringList Class (cont’d)
CStringList(AFXCOLL.H)
– 멤버
CNode structure
– 실제 list에서의 한 node를 위한 structure
m_pNodeHead
– List에서의 처음 element에 대한 node pointer
m_pNodeTail
– List에서의 마지막 element에 대한 node pointer
m_nCount
– List에서의 element의 수
[56]
비트교육센터
CStringList Class (cont’d)
– CPlex structure(AFXPLEX_.H)
struct CPlex
{
CPlex* pNext;
void* data() { return this+1; }
static CPlex* PASCAL
Create(CPlex*& head, UINT nMax, UINT cbElement);
void FreeDataChain();
// free this one and links
};
[57]
비트교육센터
CStringList Class (cont’d)
– NewNode()의 이해
CStringList::CNode*
CStringList::NewNode(CStringList::CNode* pPrev, CStringList::CNode* pNext)
{
if (m_pNodeFree == NULL) {
// add another block
CPlex* pNewBlock = CPlex::Create(m_pBlocks, m_nBlockSize,
sizeof(CNode));
// chain them into free list
CNode* pNode = (CNode*) pNewBlock->data();
// free in reverse order to make it easier to debug
pNode += m_nBlockSize - 1;
for (int i = m_nBlockSize-1; i >= 0; i--, pNode--)
{
pNode->pNext = m_pNodeFree;
m_pNodeFree = pNode;
}
비트교육센터
}
[58]
CStringList Class (cont’d)
ASSERT(m_pNodeFree != NULL); // we must have something
CStringList::CNode* pNode = m_pNodeFree;
m_pNodeFree = m_pNodeFree->pNext;
pNode->pPrev = pPrev;
pNode->pNext = pNext;
m_nCount++;
ASSERT(m_nCount > 0); // make sure we don't overflow
ConstructElement(&pNode->data);
return pNode;
}
[59]
비트교육센터
CStringList Class (cont’d)
CStringList::NewNode()(LIST_S.CPP)
– CStringList의 memory 관리의 핵심
– Add(), Insert() 등의 함수가 위 함수를 내부적으로 이용
– MFC list는 free CNode element로 이루어진 singly linked list를 유지하고 있
다.(m_pNodeFree)
– Free node가 없으면
CPlex::Create()함수를 이용하여 메모리 할당
할당된 메모리를 list형태로 변환 후 head를 m_pNodeFree가 가리키게 함
POSITION
– 내부적으로 CNode에 대한 pointer 역할
[60]
비트교육센터
CStringList Class (cont’d)
CPlex* PASCAL CPlex::Create(CPlex*& pHead, UINT nMax, UINT cbElement)
{
CPlex* p = (CPlex*) new BYTE[sizeof(CPlex) + nMax * cbElement];
p->pNext = pHead;
pHead = p; // change head (adds in reverse order for simplicity)
return p;
}
[61]
비트교육센터
CStringList Class (cont’d)
Delete시의 memory관리
– Element가 delete되면 memory는 그대로 두고 free node list에 추가
– CStringList::RemoveAll()함수에서 실제 memory를 free함(Data list & free
list를 free)
void CStringList::RemoveAll()
{
ASSERT_VALID(this);
// destroy elements
CNode* pNode;
for (pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
DestructElement(&pNode->data);
m_nCount = 0;
m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
m_pBlocks->FreeDataChain();
m_pBlocks = NULL;
}
[62]
비트교육센터
CStringList Class (cont’d)
List memory 관리 요약
– 세개의 list를 관리한다.
Actual in-use list
– Doubly linked list of CNodes
– m_pNodeHead, m_pNodeTail
List of free nodes
– Singly linked list of CNodes(m_pNodeFree)
All allocated memory blocks
– Singly linked list of CPlexes(m_pBlocks)
[63]
비트교육센터
Map Collections
Map collections
– CMapPtrToPtr, CMapStringToOb
– CMapStringToPtr, CMapStringToString
– CMapWordToOb, CMapWordToPtr
특징
– Dictionary라고 불리기도 함
– Key, value 쌍을 하나의 단위(association)로 저장함
– Hash table을 이용함
[64]
비트교육센터
Map Collections (cont’d)
예제
CMapStringToString myStringMap;
myStringMap.SetAt(“one”, “uno”);
myStringMap.SetAt(“two”, “dos”);
myStringMap.SetAt(“three”, “tres”);
Cstring strAnswer;
if ( myStringMap.LookUp(“one”, answer) )
// got it, should be uno
else
….
// Iterative
POSITION pos = GetStartPosition();
while ( pos != NULL ) {
CString key, value;
GetNextAssoc(pos, key, value);
…
}
[65]
비트교육센터
Map Collections (cont’d)
class CMapWordToPtr : public CObject
{
DECLARE_DYNAMIC(CMapWordToPtr)
protected:
// Association
struct CAssoc {
CAssoc* pNext;
WORD key;
void* value;
};
public:
CMapWordToPtr(int nBlockSize = 10);
int GetCount() const;
BOOL IsEmpty() const;
// Lookup
BOOL Lookup(WORD key, void*& rValue) const;
// Operations
// Lookup and add if not there
void*& operator[](WORD key);
[66]
비트교육센터
Map Collections (cont’d)
void SetAt(WORD key, void* newValue);
BOOL RemoveKey(WORD key);
void RemoveAll();
POSITION GetStartPosition() const;
void GetNextAssoc(POSITION& rNextPosition,
WORD& rKey, void*& rValue) const;
UINT GetHashTableSize() const;
void InitHashTable(UINT hashSize, BOOL bAllocNow = TRUE);
protected:
CAssoc** m_pHashTable;
UINT m_nHashTableSize;
int m_nCount;
CAssoc* m_pFreeList;
struct CPlex* m_pBlocks;
int m_nBlockSize;
CAssoc* NewAssoc();
void FreeAssoc(CAssoc*);
CAssoc* GetAssocAt(WORD, UINT&) const;
};
[67]
비트교육센터
Map Collections (cont’d)
CMapWordToPtr(AFXCOLL.H)
– 멤버
CAssoc structure
– Map의 element를 나타내는 structure
– Memory management
List와 동일(CPlex 이용)
– Map Hashing
내부적으로 hash table을 생성(Array of CAssoc pointer)
InitHashTable()(MAP_WP.CPP)
m_pHashTable, m_nHashTableSize
[68]
비트교육센터
Map Collections (cont’d)
Word와 string에 대한 각각의 hash function이 존재(HashKey()함수)
Collision의 해결
– Linked list of collided items
– CAssoc의 pNext멤버 변수
거의 모든 insert는 operator[]를 이용한다.
operator[]
– Collision해결 코드가 들어가 있다.
_AFXCOLL_INLINE void CMapWordToPtr::SetAt(WORD key, void* newValue)
{ (*this)[key] = newValue; }
[69]
비트교육센터
CFile Class Family
CFile class family
– CFile
Nonbuffered file access (Windows API)
– CStdioFile
Buffered I/O로 CFile을 발전시킴
– CMemFile, CSharedFile
Shared memory를 CFile interface로 구현
[70]
비트교육센터
CFile Class
class CFile : public CObject
{
DECLARE_DYNAMIC(CFile)
public:
enum OpenFlags {
modeRead =
0x0000,
modeWrite =
0x0001,
modeReadWrite =
0x0002,
shareCompat =
0x0000,
shareExclusive = 0x0010,
shareDenyWrite = 0x0020,
shareDenyRead =
0x0030,
shareDenyNone =
0x0040,
modeNoInherit =
0x0080,
modeCreate =
0x1000,
modeNoTruncate = 0x2000,
typeText =
0x4000,
typeBinary = (int)0x8000
};
enum Attribute {
normal = 0x00,
readOnly = 0x01,
hidden = 0x02,
system = 0x04,
volume = 0x08,
directory = 0x10,
archive = 0x20
};
enum SeekPosition
{ begin = 0x0, current = 0x1, end = 0x2 };
enum { hFileNull = -1 };
// Constructors
CFile();
CFile(int hFile);
CFile(LPCTSTR lpszFileName,
UINT nOpenFlags);
[71]
비트교육센터
CFile Class (cont’d)
// Attributes
UINT m_hFile;
operator HFILE() const;
virtual DWORD GetPosition() const;
BOOL GetStatus(CFileStatus& rStatus) const;
virtual CString GetFileName() const;
virtual CString GetFileTitle() const;
virtual CString GetFilePath() const;
virtual void SetFilePath(LPCTSTR lpszNewName);
// Operations
virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags,
CFileException* pError = NULL);
static void PASCAL Rename(LPCTSTR lpszOldName,
LPCTSTR lpszNewName);
static void PASCAL Remove(LPCTSTR lpszFileName);
static BOOL PASCAL GetStatus(LPCTSTR lpszFileName,
CFileStatus& rStatus);
static void PASCAL SetStatus(LPCTSTR lpszFileName,
const CFileStatus& status);
[72]
비트교육센터
CFile Class (cont’d)
DWORD SeekToEnd();
void SeekToBegin();
virtual LONG Seek(LONG lOff, UINT nFrom);
virtual void SetLength(DWORD dwNewLen);
virtual DWORD GetLength() const;
virtual UINT Read(void* lpBuf, UINT nCount);
virtual void Write(const void* lpBuf, UINT nCount);
virtual void Abort();
virtual void Flush();
virtual void Close();
enum BufferCommand
{ bufferRead, bufferWrite, bufferCommit, bufferCheck };
virtual UINT GetBufferPtr(UINT nCommand, UINT nCount = 0,
void** ppBufStart = NULL, void** ppBufMax = NULL);
protected:
BOOL m_bCloseOnDelete;
CString m_strFileName;
};
[73]
비트교육센터
CFile Class (cont’d)
Declaration of CFile(AFX.H)
– 멤버
m_hFile
– Windows file handle
BufferCommand, GetBufferPtr()
– CMemFile의 기능을 위한 멤버
m_bCloseOnDelete
– CFile object가 destroy될 때 file handle을 close할 지를 나타냄
m_strFileName
– File name
[74]
비트교육센터
CFile Class (cont’d)
– Operations
거의 모든 operator들이 window API를 내부적으로 그대로 호출하는 수준
Open()  ::Createfile()
Read()  ::ReadFile()
Write()  ::WriteFile()
[75]
비트교육센터
CFile Operation (cont’d)
Opening
char* pszFileName = "c:\\test\\myfile.dat";
CFile myFile;
CFileException fileException;
if(!myFile.Open(pszFileName, CFile::modeCreate|CFile::modeReadWrite,
&fileException)){
TRACE( "Can't open file %s, error = %u\n", pszFileName, fileException.m_cause );
}
Reading & Writing
char
szBuffer[256];
UINT
nActual = 0;
CFile myFile;
myFile.Write( szBuffer, sizeof( szBuffer ) );
myFile.Seek( 0, CFile::begin );
nActual = myFile.Read( szBuffer, sizeof( szBuffer ) );
[76]
비트교육센터
CFile Operation (cont’d)
File status
CFile theFile;
char* szFileName = "c:\\test\\myfile.dat";
BOOL bOpenOK;
CFileStatus status;
if( CFile::GetStatus( szFileName, status ) )
{
// Open the file without the Create flag
bOpenOK = theFile.Open( szFileName,
CFile::modeWrite );
}
else
{
// Open the file with the Create flag
bOpenOK = theFile.Open( szFileName,
CFile::modeCreate | CFile::modeWrite );
}
[77]
비트교육센터
CStdioFile
CFile과의 차이점
– Wrapping C run-time library(fopen,…)
– Buffered I/O
– ReadString()과 WriteString()함수 지원
Text mode로 파일을 열면 string의 read/write를 지원
– Buffering지원으로 인해 몇 개의 function은 쓸 수 없다.
[78]
비트교육센터
CStdioFile(contd.)
Declaration of CStdioFile(AFX.H)
– 멤버
m_pStream
– FILE pointer
ReadString(), WriteString()(FILETXT.CPP)
LPTSTR CStdioFile::ReadString(LPTSTR lpsz, UINT nMax)
{
LPTSTR lpszResult = _fgetts(lpsz, nMax, m_pStream);
if (lpszResult == NULL && !feof(m_pStream))
{
clearerr(m_pStream);
AfxThrowFileException(CFileException::generic, _doserrno,
m_strFileName);
}
return lpszResult;
}
[79]
비트교육센터
CMemFile
존재 이유
– MFC의 serialization기능을 memory에 이용하기 위해
Declaration of CMemFile(AFX.H)
– 멤버
m_nGrowBytes
– 내부 buffer의 증가 단위
m_nPosition
– Memory block에서의 file pointer
[80]
비트교육센터
CMemFile(contd.)
m_nBufferSize
– Buffer의 크기
m_nFileSize
– Logical memory file의 크기
– m_nFileSize <= m_nBufferSize
m_nlpBuffer
– Buffer에 대한 pointer
m_bAutoDelete
– Destructor가 호출될 때 memory를 free할 건지를 나타냄
[81]
비트교육센터
CMemFile(contd.)
– Memory handling
CArray memory handling과 유사
GrowFile()(FILEMEM.CPP)
– Memory 할당의 단위는 m_nGrowBytes 크기
– 이미 할당되어 있으면 realloc
Read()(FILEMEM.CPP)
– 지정한 크기 만큼 buffer에서 읽어서 넘겨줌
– File에 대한 작업과 interface는 동일
[82]
비트교육센터
CSharedFile
특징
– CMemFile에서 상속을 받음
– Windows global memory API를 사용
GlobalAlloc(), GlobalReAlloc(), …
– OLE 기능 구현에 이용됨
– AFXPRIV.H
[83]
비트교육센터
4. CException class
CException
– 모든 exception처리 class의 부모
종류
–
–
–
–
–
–
–
CArchiveException – Serialization exception
CDaoException – Data access object exception
CDBException – Database exception
CFileException – File exception
CMemoryException – Memory exception
CNotSupportedException – Something is not supported
…
[84]
비트교육센터
CException
Declaration of CException(AFX.H)
– 멤버
GetErrorMessage()
– Exception에 해당하는 message string을 가져옴
ReportError()
– Message 출력
예:CFileException(AFX.H)
– 가능한 exception을 enumeration type으로 가지고 있다.
[85]
비트교육센터
CException(contd.)
– Exception발생시 AfxThrowFileException()함수를 호출
– AfxThrowFileException()(FILEX.CPP)
적절한 처리후 throw 함
– 해당 catch 내부의 문이 수행됨
– 멤버
m_cause
– Enumerated Cfile exception
m_strFileName
– Exception을 발생시킨 file name
[86]
비트교육센터
CException(contd.)
//…
CMemFile myMemFile;
try
{
//…
myMemFile.Seek(2043);
//…
}
catch (CFileException, e)
{
if (e->m_cause == CFileException::badSeek)
…
e->Delete();
}
END_CATCH
[87]
비트교육센터
Chapter
05
모든 길은 Cobject로 통한다
Contents
Introduction
CObject features
–
–
–
–
RTCI
Dynamic creation
Persistence
Diagnostics
[89]
비트교육센터
Introduction
CObject Class
– 대부분의 MFC class들의 최상위 부모 class
singly rooted hierarchy
– 대부분의 MFC class들에게 필요한 기능 구현
– 문제점
가상 테이블의 거대화와 성능 저하
Poor object-oriented design
[90]
비트교육센터
CObject Features
Run-time class information (RTCI)
Dynamic creation
Persistence (serialization)
Diagnostic support
[91]
비트교육센터
CObject Class
AFX.H
class CObject
{
public:
// Object model (types, destruction, allocation)
virtual CRuntimeClass* GetRuntimeClass() const;
virtual ~CObject(); // virtual destructors are necessary
// Diagnostic allocations
void* PASCAL operator new(size_t nSize);
void* PASCAL operator new(size_t, void* p);
void PASCAL operator delete(void* p);
protected:
CObject();
[92]
비트교육센터
CObject Class (cont’d)
private:
CObject(const CObject& objectSrc);
void operator= (const CObject& objectSrc);
// Attributes
public:
BOOL IsSerializable() const;
BOOL IsKindOf(const CRuntimeClass* pClass) const;
virtual void Serialize(CArchive& ar);
// Diagnostic Support(디버깅용 함수)
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
public:
static const AFX_DATA CRuntimeClass classCObject;
static CRuntimeClass* PASCAL _GetBaseClass();
};
[93]
비트교육센터
Macro
두가지 메크로가 있다.
DECLARE macro
–
–
Class에 멤버 변수와 함수를 선언
Header(Interface) file에 존재
IMPLEMENT macro
–
–
Class의 멤버 변수와 함수를 구현
C++ file에 존재
–
–
–
DECLARE_DYNAMIC / IMPLEMENT_DYNAMIC
DECLARE_DYNCREATE / IMPLEMENT_DYNCREATE
DECLARE_SERIAL / IMPLEMENT_SERIAL
종류
[94]
비트교육센터
Macro (cont’d)
세 Macro의 포함 관계
RTCI
Dynamic
Creation
Serialization
“DYNAMIC”
O
X
X
“DYNCREATE”
O
O
X
“SERIAL”
O
O
O
[95]
비트교육센터
Run-Time Class Information (RTCI)
정의
– 개발자는 어떤 object의 class name, parent 같은 정보를 run time에 알 수 있다.
Run-Time Type Information (RTTI)
– C++ language의 특성
– RTCI와 동일한 기능
– 향후 통합 가능성
[96]
비트교육센터
RTCI 사용 예
// Header file
Class CMyClass : public CObject
{
DECLARE_DYNAMIC(CMyClass)
// Macro 1
Public:
CMyClass();
// …
}
// Implementation file
IMPLEMENT_DYNAMIC(CMyClass, CObject)
// Macro 2
DemoRTCI()
{
CObject* pObject = new CMyClass;
// Macro 3
if (pObject->IsKindOf(RUNTIME_CLASS(CMyClass))) {
CMyClass* pMyObject = (CMyClass*)pObject;
}
}
비트교육센터
[97]
RTCI 과정
CMyClass가 들어왔다.
AFX.H
#define DECLARE_DYNAMIC(class_name) \
public: \
static const AFX_DATA CRuntimeClass class##class_name; \
virtual CRuntimeClass* GetRuntimeClass() const; \
Preprocessor
Class_name : CMyClass
public:
static const AFX_DATA CRuntimeClass classCMyClass;
virtual CRuntimeClass* GetRuntimeClass() const;
[98]
비트교육센터
RTCI 과정 (cont’d)
CMyClass,
CObject
#define IMPLEMENT_DYNAMIC(class_name, base_class_name) \
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, NULL)
#define IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, \
wSchema, pfnNew) \
AFX_COMDAT const AFX_DATADEF CRuntimeClass \
class_name::class##class_name = { \
#class_name, sizeof(class class_name), wSchema, pfnNew, \
RUNTIME_CLASS(base_class_name), NULL }; \
 6개의 정보가 만들어지는 클래스이다.
CRuntimeClass* class_name::GetRuntimeClass() const \
{ return RUNTIME_CLASS(class_name); } \
#define RUNTIME_CLASS(class_name) 밑의 주소를 리턴
((CRuntimeClass*)(&class_name::class##class_name))
[99]
비트교육센터
RTCI 과정 (cont’d)
AFX_COMDAT const AFX_DATADEF CRuntimeClass CMyClass::classCMyClass =
{
“CMyClass”, sizeof(CMyClass), 0xFFFF, NULL,
&CObject::classCObject, NULL
};
CRunTimeClass* CMyClass::GetRuntimeClass() const
{
return &CMyClass::classCMyClass;
}
CMyClass::classCMyClass
m_lpszClassName
m_nObjectSize
m_wSchema
m_pfnCreateObject
m_pBaseClass
=
=
=
=
=
“CMyClass”
sizeof(CMyClass)
0xFFFF
NULL
RUNTIME_CLASS(CObject) Cobject::classCObject비트교육센터
[100]
CRuntimeClass
AFX.H
struct CRuntimeClass
{
// Attributes
LPCSTR
m_lpszClassName;
int
m_nObjectSize;
UINT
m_wSchema; // schema number of the loaded class
CObject* (PASCAL* m_pfnCreateObject)(); // NULL=>abstract class
CRuntimeClass* m_pBaseClass;
// Operations
CObject* CreateObject();
BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;
// Implementation
void Store(CArchive& ar) const;
CRuntimeClass* m_pNextClass;
// linked list of registered classes
};
[101]
비트교육센터
CObject::IsKindOf()
OBJCORE.CPP
– VC 4.0까지는 다른 내용이었음
BOOL CObject::IsKindOf(const CRuntimeClass* pClass) const
{
ASSERT(this != NULL);
// it better be in valid memory, at least for CObject size
ASSERT(AfxIsValidAddress(this, sizeof(CObject)));
// simple SI case
CRuntimeClass* pClassThis = GetRuntimeClass();
return pClassThis->IsDerivedFrom(pClass);
 런타임클레스와 런타임클레스와의 비교
}
[102]
비트교육센터
CRuntimeClass::IsDerivedFrom()
OBJCORE.CPP
BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const
{
// simple SI case
const CRuntimeClass* pClassThis = this;
 현재의 포인터를 가져온다.(CMyClass의 변수의 주소)
while (pClassThis != NULL)
{
if (pClassThis == pBaseClass) 조사하고자 하는 주소와 같냐?
return TRUE;
pClassThis = pClassThis->m_pBaseClass;
 다르면 베이스클레스(Cobect) 로 간다.
 다시 While문을 돌아서 Cobject의 포인터를 리턴하겠지?
}
return FALSE;
// walked to the top, no match
}
[103]
비트교육센터
Dynamic Creation
Object의 동적 생성
– CRuntimeClass의 정보를 가지고 object를 동적으로 생성할 수 있
다.(CreateObject())
RTCI macro
– DECLARE_DYNCREATE
IMPLEMENT_DYNCREATE
DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC보다 상위에 있는 macro
따라서 위 macro는 자동 포함됨
[104]
비트교육센터
Dynamic Creation 사용 예
CMyClass가 DYNCREATE macro를 사용
CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CMyClass);
Cobject* pObject = pRuntimeClass->CreateObject();
ASSERT(pObject->IsKindOf(RUNTIME_CLASS(CMyClass)));
 CMyClass의 타입이냐?? True리턴
pDocTemplate = new CMultiDocTemplate(IDR_SCRIBTYPE,
RUNTIME_CLASS(CScribDoc),
RUNTIME_CLASS(CMDIChildWnd),
RUNTIME_CLASS(CScribView));
[105]
비트교육센터
Dynamic Creation 과정
AFX.H
#define DECLARE_DYNCREATE(class_name) \  맴버변수를 만들어줌
DECLARE_DYNAMIC(class_name) \ ->GetRuntime…
static CObject* PASCAL CreateObject();
 그리고 CMyClass의 맴버함수추가
Preprocessor
Class_name : CMyClass
public:
static const AFX_DATA CRuntimeClass classCMyClass;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
[106]
비트교육센터
Dynamic Creation 과정 (cont’d)
#define IMPLEMENT_DYNCREATE(class_name, base_class_name) \
CObject* PASCAL class_name::CreateObject() \
{ return new class_name; } \  new CMyClass
IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \
class_name::CreateObject)  새로추가된 함수를 넣어줌
m_lpszClassName
m_nObjectSize
m_wSchema
m_pfnCreateObject
m_pBaseClass
=
=
=
=
=
“CMyClass”
sizeof(CMyClass)
0xFFFF
CMyClass::CreateObject
RUNTIME_CLASS(CObject)
이젠 NULL이 아니라 위와 같은 값이 들어가게 된다.
[107]
비트교육센터
CRuntimeClass::CreateObject()
OBJCORE.CPP
CObject* CRuntimeClass::CreateObject()
{
if (m_pfnCreateObject == NULL)
 앞의 4번째 인자값: NULL이 아니쥐.
return NULL;
CObject* pObject = NULL;
TRY
{
pObject = (*m_pfnCreateObject)();
 전장에 설치한 함수 리턴
}
END_TRY
return pObject;
}
[108]
비트교육센터
Persistence
Persistence란?
– Object의 state정보를 저장(store)했다가 나중에 복원(recover)할 수 있는 능력
– MFC에서 말하는 serialization
– Format에 신경쓰지 않고 object자체를 파일에 읽고 쓸 수 있게 한다.
모든 일은 내부적으로 처리됨
– 관련 멤버함수
IsSerializable()
Serialize()
[109]
비트교육센터
Serialization의 지원
다음의 두 가지 작업
– DECLARE_SERIAL / IMPLEMENT_SERIAL macro를 이용한다. 이 때,
schema(버전 정보)를 반드시 넣는다.
– CObject::Serialize()함수를 override한다.
자신의 class data member에 맞게
[110]
비트교육센터
Serialization 예
// Header file
class CMyClass : public CObject
{
DECLARE_SERIAL(CMyClass)
public:
CMyClass();
WORD
m_wType;
DWORD
m_dwData;
CPoint
m_ptMiddle;
void
Serialize(CArchive &);
}
위와 같이 CMyClass를 만든다.
[111]
비트교육센터
Serialization 예(cont’d)
3번째 인자인 스키마값
// Implementation file
IMPLEMENT_SERIAL(CMyClass, CObject, 0xabcd)
void CMyClass::Serialize(CArchive& ar)
{
if (ar.IsStoring()) {
ar << m_wType;
ar << m_dwData;
ar << m_ptMiddle;
}
else {
ar >> m_wType;
ar >> m_dwData;
ar >> m_ptMiddle;
}
}
[112]
비트교육센터
CArchive Class
AFX.H
목적
– Binary stream ( not ASCII stream )
– Tied to CFile pointer
– Implementing buffering of data
[113]
비트교육센터
CArchive Class (cont’d)
class CArchive
{
public:
// Flag values
enum Mode{store = 0, load = 1, bNoFlushOnDelete = 2, bNoByteSwap = 4};
CArchive(CFile* pFile, UINT nMode, int nBufSize = 4096, void* lpBuf=NULL);
~CArchive();
// Attributes
BOOL IsLoading() const;
BOOL IsStoring() const;
BOOL IsByteSwapping() const;
BOOL IsBufferEmpty() const;
CFile* GetFile() const;
UINT GetObjectSchema(); // only valid when reading a CObject*
void SetObjectSchema(UINT nSchema);
[114]
비트교육센터
CArchive Class (cont’d)
CDocument* m_pDocument;
UINT Read(void* lpBuf, UINT nMax);
void Write(const void* lpBuf, UINT nMax);
void Flush();
void Close();
void WriteString(LPCTSTR lpsz);
LPTSTR ReadString(LPTSTR lpsz, UINT nMax);
BOOL ReadString(CString& rString);
public:
friend CArchive& AFXAPI operator<<(CArchive& ar, const CObject* pOb);
friend CArchive& AFXAPI operator>>(CArchive& ar, CObject*& pOb);
friend CArchive& AFXAPI operator>>(CArchive& ar, const CObject*& pOb);
// insertion operations
CArchive& operator<<(BYTE by);
CArchive& operator<<(WORD w);
CArchive& operator<<(LONG l);
CArchive& operator<<(DWORD dw);
CArchive& operator<<(float f);
CArchive& operator<<(double d);
[115]
비트교육센터
CArchive Class (cont’d)
CArchive& operator<<(int i);
CArchive& operator<<(short w);
CArchive& operator<<(char ch);
CArchive& operator<<(unsigned u);
// extraction operations
CArchive& operator>>(BYTE& by);
CArchive& operator>>(WORD& w);
CArchive& operator>>(DWORD& dw);
CArchive& operator>>(LONG& l);
CArchive& operator>>(float& f);
CArchive& operator>>(double& d);
CArchive& operator>>(int& i);
CArchive& operator>>(short& w);
CArchive& operator>>(char& ch);
CArchive& operator>>(unsigned& u);
// object read/write
CObject* ReadObject(const CRuntimeClass* pClass);
void WriteObject(const CObject* pOb);
// advanced object mapping (used for forced references)
void MapObject(const CObject* pOb);
[116]
비트교육센터
CArchive Class (cont’d)
void WriteClass(const CRuntimeClass* pClassRef);
CRuntimeClass* ReadClass(const RuntimeClass*pClassRefRequested=NULL, UINT* pSchema = NULL,
DWORD* pObTag = NULL);
void SerializeClass(const CRuntimeClass* pClassRef);
void SetStoreParams(UINT nHashSize = 2053, UINT nBlockSize = 128);
void SetLoadParams(UINT nGrowBy = 1024);
// Implementation
public:
BOOL m_bForceFlat; // for COleClientItem implementation (default TRUE)
BOOL m_bDirectBuffer; // TRUE if m_pFile supports direct buffering
void FillBuffer(UINT nBytesNeeded);
void CheckCount(); // throw exception if m_nMapCount is too large
DWORD ReadCount();
void WriteCount(DWORD dwCount);
UINT m_nObjectSchema;
CString m_strFileName;
protected:
CArchive(const CArchive& arSrc);
void operator=(const CArchive& arSrc);
BOOL m_nMode;
BOOL m_bUserBuf;
[117]
비트교육센터
CArchive Class (cont’d)
int m_nBufSize;
CFile* m_pFile;
BYTE* m_lpBufCur;
BYTE* m_lpBufMax;
BYTE* m_lpBufStart;
// array/map for CObject* and CRuntimeClass* load/store
UINT m_nMapCount;
union
{
CPtrArray* m_pLoadArray;
//read할떄 쓰고
CMapPtrToPtr* m_pStoreMap;
//Write할때
};
// map to keep track of mismatched schemas
CMapPtrToPtr* m_pSchemaMap;
// advanced parameters (controls performance with large archives)
UINT m_nGrowSize;
UINT m_nHashSize;
};
[118]
비트교육센터
CArchive Class (cont’d)
Members
– m_nMode
읽기인지 쓰기인지 결정
– IsLoading(), IsStoring(), IsByteSwapping(), IsBufferEmpty()
CArchive object의 state access함수
[119]
비트교육센터
CArchive Class (cont’d)
– Operators
CObject, Windows data type, C++ data type에 대한 insertion, extraction
operator
– Class member functions
WriteClass(), ReadClass(), SerializeClass()
CRuntimeClass structure의 정보를 읽고 쓰기 위한 함수
– Map members
이미 저장되었거나 읽혀진 object의 정보를 빠르게 얻기 위한 mapping정보 관
리
[120]
비트교육센터
CArchive Class (cont’d)
WORD type에 대한 함수 예 (INCLUDE\AFX.INL)
_AFX_INLINE CArchive& CArchive::operator<<(WORD w)
{
if (m_lpBufCur + sizeof(WORD) > m_lpBufMax)
Flush();
*(UNALIGNED WORD*)m_lpBufCur = w;
m_lpBufCur += sizeof(WORD);
return *this;
}
_AFX_INLINE CArchive& CArchive::operator>>(WORD& w)
{
if (m_lpBufCur + sizeof(WORD) > m_lpBufMax)
FillBuffer(sizeof(WORD) - (UINT)(m_lpBufMax - m_lpBufCur));
w = *(UNALIGNED WORD*)m_lpBufCur;
m_lpBufCur += sizeof(WORD);
return *this;
}
[121]
비트교육센터
Serialization 과정
Serialization macro(AFX.H)
#define DECLARE_SERIAL(class_name) \
_DECLARE_DYNCREATE(class_name) \
AFX_API friend CArchive& AFXAPI operator>> (CArchive& ar, class_name* &pOb);
Preprocessor
Class_name : CMyClass
public:
static const AFX_DATA CRuntimeClass classCMyClass;
virtual CRuntimeClass* GetRuntimeClass() const;
static CObject* PASCAL CreateObject();
AFX_API friend Carchive& AFXAPI operator>> (Carchive& ar, CMyClass* &pOb);
[122]
비트교육센터
Serialization 과정(cont’d)
#define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \
CObject* PASCAL class_name::CreateObject() \
더 이상 NULL이 아니다.
{ return new class_name; } \
_IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, wSchema, \
class_name::CreateObject) \
AFX_CLASSINIT _init_##class_name(RUNTIME_CLASS(class_name)); \
CArchive& AFXAPI operator>> (CArchive& ar, class_name* &pOb) \
{ pOb = (class_name*)ar.ReadObject(RUNTIME_CLASS(class_name)); \
return ar; } \
Preprocessor
Class_name : CMyClass
CArchive& AFXAPI operator>> (CArchive& ar, CMyClass* &pOb)
{
pOb = (CMyClass*)ar.ReadObject(RUNTIME_CLASS(CMyClass));
return ar;
}
비트교육센터
[123]
Serialization 과정(cont’d)
CArchive::ReadObject()(ARCOBJ.CPP)
CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested)
{
UINT nSchema;
DWORD obTag;
CRuntimeClass* pClassRef =
ReadClass(pClassRefRequested, &nSchema, &obTag);
pOb = pClassRef->CreateObject();
UINT nSchemaSave = m_nObjectSchema;
m_nObjectSchema = nSchema;
pOb->Serialize(*this);
m_nObjectSchema = nSchemaSave;
return pOb;
}
[124]
비트교육센터
Serialization 과정(cont’d)
Macro에 insertion operator가 없는 이유
– Global insertion operator가 존재함(AFX.INL)
– 특별히 CRuntimeClass정보를 필요로 하지 않기 때문
CObject에 대한 insertion operator로 충분함
_AFX_INLINE CArchive& AFXAPI operator<< (CArchive& ar, const CObject* pOb)
{
ar.WriteObject(pOb);
return ar;
}
[125]
비트교육센터
Serialization 과정(cont’d)
void CArchive::WriteObject(const CObject* pOb)
{
if (pOb == NULL) *this << wNullTag;
else if ((nObIndex = (DWORD)(*m_pStoreMap)[(void*)pOb]) != 0) {
// save out index of already stored object
if (nObIndex < wBigObjectTag)
*this << (WORD)nObIndex;
else {
*this << wBigObjectTag;
*this << nObIndex;
}
} else {
// write class of object first
CRuntimeClass* pClassRef = pOb->GetRuntimeClass();
WriteClass(pClassRef);
// enter in stored object table, checking for overflow
CheckCount();
(*m_pStoreMap)[(void*)pOb] = (void*)m_nMapCount++;
// cause the object to serialize itself
((CObject*)pOb)->Serialize(*this);
}
}
[126]
비트교육센터
CObject and Serialization
CObject::IsSerializable()
– OBJCORE.CPP
CObject::Serialize()
– AFX.INL
BOOL CObject::IsSerializable() const
{
return (GetRuntimeClass()->m_wSchema != 0xffff);
}
_AFX_INLINE void CObject::Serialize(CArchive&)
{
/* CObject does not serialize anything by default */
}
[127]
비트교육센터
Read & Write 추적
목적 및 가정
– Serialization의 진행 과정 이해
– Document/View architecture 가정
– 우리의 document class가 다음의 멤버 변수를 가짐
CMyClass* m_pMyClass;
class CMyClass : public CObject
{
DECLARE_SERIAL(CMyClass)
public:
CMyClass();
WORD
m_wType;
DWORD
m_dwData;
CPoint
m_ptMiddle;
void
Serialize(CArchive &);
}
[128]
비트교육센터
Read & Write 추적 (cont’d)
void CMyDocument::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_pMyClass;
}
else
{
ar >> m_pMyClass;
}
}
[129]
비트교육센터
Read 과정
“DOCCORE.cpp”
BOOL CDocument::OnOpenDocument(LPCTSTR lpszPathName)
{
CFile* pFile=GetFile(…);
DeleteContents();
SetModifiedFlag(); // dirty during de-serialize
CArchive loadArchive(pFile, CArchive::load |
CArchive::bNoFlushOnDelete);
loadArchive.m_pDocument = this;
loadArchive.m_bForceFlat = FALSE;
CWaitCursor wait;
if (pFile->GetLength() != 0)
Serialize(loadArchive);
// load me
loadArchive.Close();
ReleaseFile(pFile, FALSE);
SetModifiedFlag(FALSE);
// start off with unmodified
return TRUE;
[130]
비트교육센터
Read 과정 (cont’d)
void CMyDocument::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_pMyClass;
}
else
{
ar >> m_pMyClass;
}
}
CArchive& AFXAPI operator>> (CArchive& ar, CMyClass* &pOb)
{
pOb = (CMyClass*)ar.ReadObject(RUNTIME_CLASS(CMyClass));
return ar;
}
[131]
비트교육센터
Read 과정 (cont’d)
CObject* CArchive::ReadObject(const CRuntimeClass* pClassRefRequested)
{
UINT nSchema;
DWORD obTag;
CRuntimeClass* pClassRef =
ReadClass(pClassRefRequested, &nSchema, &obTag);
pOb = pClassRef->CreateObject();
m_pLoadArray.InsertAt(m_nMapCount++, pOb);
UINT nSchemaSave = m_nObjectSchema;
m_nObjectSchema = nSchema;
pOb->Serialize(*this);
m_nObjectSchema = nSchemaSave;
return pOb;
}
[132]
비트교육센터
Read 과정 (cont’d)
void CMyClass::Serialize(CArchive& ar)
{
if (ar.IsStoring()) {
ar << m_wType;
ar << m_dwData;
ar << m_ptMiddle;
}
else {
ar >> m_wType;
ar >> m_dwData;
ar >> m_ptMiddle;
}
}
[133]
비트교육센터
Read 과정 (cont’d)
“AFXWIN1.INL”
_AFXWIN_INLINE CArchive& AFXAPI operator>>(CArchive& ar, POINT& point)
{ ar.Read(&point, sizeof(POINT)); return ar; }
[134]
비트교육센터
Store Operation
– Write case
CDocument::OnSaveDocument()
CArchive::CArchive()
CMyClass::Serialize()
CMyDocument::Serialize()
CArchive::IsStoring()
CArchive::IsStoring()
CArchive::operator<<(WORD)
operator<<(CArchive&, CObject*)
CArchive::operator<<(DWORD)
CArchive::WriteObject()
operator<<(CArchive&, point)
CArchive::WriteClass()
CArchive::Write()
CArchive::Close()
[135]
비트교육센터
Read Operation
– Read case
CDocument::OnOpenDocument()
CArchive::CArchive()
CMyClass::Serialize()
CMyDocument::Serialize()
CArchive::IsStoring()
CArchive::IsStoring()
CArchive::operator>>(WORD)
operator>>(CArchive&, CMyClass*)
CArchive::operator>>(DWORD)
CArchive::ReadObject()
Operator>>(CArchive&, point)
CArchive::ReadClass()
CArchive::Read()
CArchive::Close()
[136]
비트교육센터
Serialization Performance
Data structure
– Maps and arrays
– 어떤 type의 데이터를 여러 번 읽고 쓰는 경우 그 때마다 class 정보를 읽고 쓰
는 것은 비효율적
– Write
Map : reference no. + class name
MFC는 reference no.만 write
– Read
Array : CArchive는 array를 유지하며 reference no. 를 decoding하여 해당
class 정보를 획득
Serializing large data
– SetLoadParam(), SetStoreParam()
– Storing map의 hash table size나 reading array의 grow-by size 조절
[137]
비트교육센터
CRuntimeClass member 저장
State serialization
– LPCSTR m_lpszClassName
Class의 이름
– UINT m_wSchema
Class version 정보
– Store()
CRuntimeClass 의 state를 실제 저장하는 함수
– Load()
CRuntimeClass의 state를 실제 읽어 들이는 함수
– m_nObjectSize, m_pNextClass
debugging을 위해 필요
AfxAssertValidObject(), AfxDoForAllClasses()
[138]
비트교육센터
CObject Diagnostic Support
크게 2가지로 분류됨
– Basic diagnostics
Diagnostic output
– TRACE macro
– Dump() : Object 내용 전체를 찍어줌.
Run-time checking
– ASSERT macro
– AssertValid()
– ASSERT_VALID macro : 넓은 범위의 메크로
– Advanced memory diagnostics
Memory leak detection
Memory statistics
[139]
비트교육센터
Enabling Diagnostics
AfxEnableMemoryTracking
– Debug 모드에서는 diagnostic 이 적용된다.
– 그러나, 임시로 조절 가능
BOOL CWinMyApp::InitInstance()
{
#ifdef _DEBUG
// Disable tracking of memory for the scope of the InitInstance()
AfxEnableMemoryTracking(FALSE);
#endif // _DEBUG
...
#ifdef _DEBUG
// Re-enable tracking of memory
AfxEnableMemoryTracking(TRUE);
#endif // _DEBUG
}
[140]
비트교육센터
Diagnostic Output - TRACE
TRACE macro
–
–
–
–
Printf-like output
MFC tracer utility를 이용
VC++ debugger window에 결과물
예)
TRACE(“At this point, my Cpoint is : %d %d\n”, mypoint.x, mypoint.y);
[141]
비트교육센터
Inside TRACE
TRACE(AFX.H)
– 단순히 AfxTrace()라는 전역함수를 부름
#define TRACE
::AfxTrace
– AfxTrace()(DUMPOUT.CPP)
afxDump 를 이용
[142]
비트교육센터
Inside TRACE (cont’d)
void AFX_CDECL AfxTrace(LPCTSTR lpszFormat, ...)
{
#ifdef _DEBUG // all AfxTrace output is controlled by afxTraceEnabled
if (!afxTraceEnabled)
return;
#endif
va_list args;
va_start(args, lpszFormat);
int nBuf;
TCHAR szBuffer[512];
nBuf = _vsntprintf(szBuffer, _countof(szBuffer), lpszFormat, args);
ASSERT(nBuf >= 0);
if ((afxTraceFlags & traceMultiApp) && (AfxGetApp() != NULL))
afxDump << AfxGetApp()->m_pszExeName << ": ";
afxDump << szBuffer;
va_end(args);
}
[143]
비트교육센터
Inside TRACE (cont’d)
afxDump(AFX.H)
– CDumpContext의 global instance
– 최종적으로 CDumpContext의 OutputString() (DUMPCONT.CPP) 가 출력 담당
– 특정 파일에 출력도 가능
#ifdef _DEBUG
extern AFX_DATA CDumpContex afxDump;
#endif
[144]
비트교육센터
Inside TRACE (cont’d)
CDumpContext& CDumpContext::operator<<(WORD w)
{
TCHAR szBuffer[32];
wsprintf(szBuffer, _T("%u"), (UINT) w);
OutputString(szBuffer);
return *this;
}
void CDumpContext::OutputString(LPCTSTR lpsz)
{
if (!afxTraceEnabled)
return;
if (m_pFile == NULL)
{
AfxOutputDebugString(lpsz);
return;
}
m_pFile->Write(lpsz, lstrlen(lpsz)*sizeof(TCHAR));
}
[145]
비트교육센터
Diagnostic Output – Dump()
Object dump(Trace를 Object화)
–
–
–
–
CObject의 하위 클래스들이 가진 멤버함수
클래스의 state를 print하기 위해 호출
Debug build 에서만 유효
예)
[146]
비트교육센터
Diagnostic Output – Dump() (cont’d)
#ifdef _DEBUG
void CMyClass::Dump(CDumpContext& dc)
{
CObject::Dump(dc);
dc << “Type is: “ << m_wType << “\n”
<< “Data is: “ << m_dwData << “\n”
<< “Point is: “ << m_ptMiddle.x << “ “ << m_ptMiddle.y << “\n”;
}
#endif // end _DEBUG
CMyClass* pMyClass = new CMyClass;
// set some fields of the CPerson object...
//...
// now dump the contents
#ifdef _DEBUG
pMyClass->Dump( afxDump );
#endif
[147]
비트교육센터
Inside Dump()
Object dumping(OBJCORE.CPP)
#ifdef _DEBUG
void CObject::Dump(CDumpContext& dc) const
{
dc << "a " << GetRuntimeClass()->m_lpszClassName
<< " at " << (void*)this << "\n";
}
#endif //_DEBUG
단지 class이름과 주소만 출력
[148]
비트교육센터
Run-Time Checking - ASSERT
Assertion(runtime checking)
– ASSERT macro
– Run-time시의 어떤 상태를 체크하고 실패하면 warning message box가 나타난
다.
– MFC도 5000개 이상의 ASSERT문을 포함(VC++ 4)
– 사용 권유
예) window handle이 유효한지 미리 체크
// example for ASSERT
CAge* pcage = new CAge( 21 );
// CAge is derived from CObject.
ASSERT( pcage!= NULL )
ASSERT( pcage->IsKindOf( RUNTIME_CLASS( CAge ) ) )
// Terminates program only if pcage is NOT a CAge*.
[149]
비트교육센터
Inside ASSERT
#define ASSERT(f) \
do \
{\
if (!(f) && AfxAssertFailedLine(THIS_FILE, __LINE__)) \
AfxDebugBreak(); \
} while (0) \
[150]
비트교육센터
Run-Time Checking – AssertValid()
AssertValid()
– Object-validity checking
– Run-time시에 object의 멤버들의 유효성 체크
#ifdef _DEBUG
void CMyClass::AssertValid()
{
// Call inherited first
CObject::AssertValid();
ASSERT(m_wType > 0xff00);
ASSERT(m_dwData != 0);
ASSERT(m_ptMiddle.x != 0 && m_ptMiddle.y != 0);
}
#endif // End _DEBUG
[151]
비트교육센터
Inside AssertValid()
void CObject::AssertValid() const
{
ASSERT(this != NULL);
}
[152]
비트교육센터
Run-Time Checking – ASSERT_VALID
ASSERT_VALID macro
– CObject의 하위 클래스에 대해 호출 가능
– AssertValid()에 대한 호출 + 부가적인 체크
– 예를 들어 document class가 CMyClass 멤버변수를 가지면 다음과 같이 체크할
수 있다.
CMyDocument::AssertValid()
{
…
ASSERT_VALID(m_myClass);
…
}
[153]
비트교육센터
Inside ASSERT_VALID
#define ASSERT_VALID(pOb)
(::AfxAssertValidObject(pOb, THIS_FILE, __LINE__))
void AFXAPI AfxAssertValidObject(const CObject* pOb,
LPCSTR lpszFileName, int nLine)
{
if (pOb == NULL) {
if (AfxAssertFailedLine(lpszFileName, nLine))
AfxDebugBreak();
return;
// quick escape
}
if (!AfxIsValidAddress(pOb, sizeof(CObject))) // …
if (!AfxIsValidAddress(*(void**)pOb, sizeof(void*), FALSE)) // …
if (!AfxIsValidAddress(pOb, pOb->GetRuntimeClass()->m_nObjectSize,
FALSE)) // …
pOb->AssertValid();
}
[154]
비트교육센터
Detect a Memory Leak
Memory leak
– Heap에 할당된 영역을 다시 deallocate 하지 않을 때
– 할당된 메모리 영역을 이용하려 할 때
– 발견하기 무척 어려움
#ifdef _DEBUG
CMemoryState startMemState, stopMemState, diffMemState;
startMemState.Checkpoint();
#endif _DEBUG
Cstring abc = “Free me!”;
// …
#ifdef _DEBUG
stopMemState.Checkpoint();
if ( diffMemState.Difference(startMemState, stopMemState)) {
TRACE(“Memory leak!”);
}
#endif _DEBUG
[155]
비트교육센터
Specific Memory Diagnostic
afxMemDF
– memory diagnostic 의 기능을 선택적으로 하기 위한 global variable
– value
allocMemDF : Turn on memory allocator (default)
delayFreeMemDF : 프로그램이 종료할 때까지 메모리를 free하지 않음. 이를
통해 프로그램이 최대로 할당 받을 수 있는 메모리 체크 가능.
checkAlwaysMemDF : 메모리가 allocate되거나 free될 때마다 메모리 상태
체크 (AfxCheckMemory 호출)
AfxMemDF = allocMemDF | delayFreeMemDF | checkAlwaysMemDF;
[156]
비트교육센터
Review Memory Statics
CMemoryState class
– DumpStatistics()
delay 된 메모리의 양
heap에 남아 있는 양
program에 필요한 메모리 양 등등…
– DumpAllObjectsSince()
지금까지 할당된 모든 object들의 기록 표시
가장 최근의 CMemoryState::Checkpoint() 부터 기록
[157]
비트교육센터
예
// Frame variable : do your memory allocations and deallocations
CString s = "This is a frame variable";
// Heap variable : the next object is a heap object
CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
if( diffMemState.Difference( oldMemState, newMemState ) ) {
TRACE( "Memory leaked!\n" );
diffMemState.DumpAllObjectsSince();
}
Dumping objects ->
////// Cperson::Dump()
{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4
Last Name: Smith
First Name: Alan
Phone #: 581-0215
{1} strcore.cpp(80) : non-object block at $00A7516E, 25 bytes long
[158]
비트교육센터
Inside Memory Diagnostics
CMemoryState class
– AFX.H
– 모든 memory allocation에 대한 개수와 크기 정보를 가지고 있다.
new operator 를 override함으로 인해서 가능
– Debugging상태에서는 new 를 DEBUG_NEW로 대체함
#ifdef _DEBUG
#define new DEBUG_NEW
#endif //_DEBUG
[159]
비트교육센터
Inside Memory Diagnostics (cont’d)
AFX.H
– DEBUG_NEW declaration
파일 이름과 라인을 저장함
– Global new operator
– CObject::operator new
또 다른 debug new operator
객체인지 체크
내부적으로 호출하는 AfxAllocMemoryDebug()함수의 argument차이
#define DEBUG_NEW new(THIS_FILE, __LINE__)
void* operator new(size_t, nSize, PCSTR lpszFileName, int nLine)
[160]
비트교육센터
Advanced memory…(contd.)
– AfxAllocMemoryDebug() (AFXMEM.CPP)
Malloc(sizeof(CBlockHeader) + nSize + nNoMansLandSize);
CBlockHeader부분에 debugging시 필요한 모든 정보를 저장함
No mans land부분에 overwrite 체크를 위한 정보를 저장함
할당하는 모든 메모리 block들을 리스트로 연결
CBlockHeader
Gap
데이터를 위한 부분
[161]
No Mans Land
비트교육센터