Presentation is loading. Please wait.

Presentation is loading. Please wait.

Chap. 4 Utility Classes. Contents  Simple value types  일반적 목적 : CString, CTime, CTimeSpan  윈도우 구조체 : CPoint, CSize, Crect  MFC collection classes.

Similar presentations


Presentation on theme: "Chap. 4 Utility Classes. Contents  Simple value types  일반적 목적 : CString, CTime, CTimeSpan  윈도우 구조체 : CPoint, CSize, Crect  MFC collection classes."— Presentation transcript:

1 Chap. 4 Utility Classes

2 Contents  Simple value types  일반적 목적 : CString, CTime, CTimeSpan  윈도우 구조체 : CPoint, CSize, Crect  MFC collection classes  array, linked list, map  CFile class family  CException class

3 Introduction  우리가 만드는 많은 class 들  Utility class 의 범주에 든다.  이 단원의 목적 MFC 개발자 들의 technique MFC 개발자 들의 technique 앞으로의 project 에 도움 앞으로의 project 에 도움

4 Simple Value Types  Simple value types  C++ type(char*, …), Windows type(RECT, …) 들을 encapsulating 한 클래스들  C++ interface 제공  더 안전하고 더 쉽게 이용할 수 있는 operator 제공 memory management memory management internationalization internationalization …

5 Class CString  Character string 을 encapsulate 함  다음과 같은 특징이 있음  Internationalization  Memory allocation/deallocation  Operators(+, =, ==, …)  String searching  String manipulation(reverse, concat)  Formatting(printf-like)

6 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;  생성

7 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()

8 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);

9 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);

10 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;

11 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);

12 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);

13 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;

14 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); };

15 CString Internals (cont’d)  CString declaration(AFX.H)  m_pchData 유일한 멤버 변수 유일한 멤버 변수 String 에 대한 pointer String 에 대한 pointer  CStringData CString 의 기능 구현을 도와주는 structure 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); } };

16 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(); }

17  AllocBuffer() 함수에 의한 memory 할당 nRefs nDataLength nAllocLength CString::m_pchData CStringDataData(nlength + 1) CString Internals (cont’d)

18  의문점 CString class 는 string 이외의 데이터를 숨김 CString class 는 string 이외의 데이터를 숨김 왜, 그들을 멤버변수로 추가하지 않았는가 왜, 그들을 멤버변수로 추가하지 않았는가 CString object 와 TCHAR * 은 똑같아야 한다. CString object 와 TCHAR * 은 똑같아야 한다.  same bits 그 이외의 부가적인 정보는 CStringData 에서 관리 그 이외의 부가적인 정보는 CStringData 에서 관리 이전 버전과의 호환성 이전 버전과의 호환성 CString Internals (cont’d)

19  Reference counting CStringData::nRefs CStringData::nRefs 실제 데이터의 변경이 가해지면 copy 실제 데이터의 변경이 가해지면 copy CString Internals (cont’d) CString myString1( “ This is a string ” ); CString myString2(myString1); CString myString3 = myString1; myString1 “This is a string” myString2 myString3

20  Reference counting 과정 nRefs 변수의 값이 -1 으로 초기화 nRefs 변수의 값이 -1 으로 초기화 그 string 에 새 참조가 발생하면 1 증가 그 string 에 새 참조가 발생하면 1 증가 참조가 줄어들면 1 감소 참조가 줄어들면 1 감소 다시 0 이 되면 삭제 가능 다시 0 이 되면 삭제 가능 참조되는 string 에 쓰기가 발생하면 새로운 string 을 생성하고 원래의 string 의 nRefs 값을 1 감소 참조되는 string 에 쓰기가 발생하면 새로운 string 을 생성하고 원래의 string 의 nRefs 값을 1 감소  Critical resource 일종의 OS 에서 발생하는 resource 공유 문제 일종의 OS 에서 발생하는 resource 공유 문제 두 thread 에서 동시에 참조를 증가 혹은 감소시키는 경우 문제 해결 두 thread 에서 동시에 참조를 증가 혹은 감소시키는 경우 문제 해결  InterlockedIncrement(), InterlockedDecrement() CString Internals (cont’d)

21  예제 CString Internals (cont’d) CString myString1( “ This is my string1 ” ); CString myString2(myString1); CString myString3; myString3 = myString2; // Write somthing myString3.MakeUpper(); Line 1 Line 2 Line 3 Line 4 Line 5

22 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)); } myString1 “This is my string1” 1

23 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; } myString1 “This is my string1” 2 myString2

24 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; } myString1 “This is my string1” 3 myString2 myString3

25 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); }

26 CString Internals (cont’d) void CString::Release() { if (GetData() != _afxDataNil) { ASSERT(GetData()->nRefs != 0); if (InterlockedDecrement(&GetData()->nRefs) <= 0) FreeData(GetData()); Init(); } myString1 “This is my string1” 2 myString2 myString3 “THIS IS MY STRING1” 1

27  Internationalization  _t internationalized string 함수를 이용하여 구현 _tcschr() => strchr() mapping _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); } CString Internals (cont’d)

28 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

29 Class CRect class CRect : public tagRECT { … typedef struct tagRECT { LONGleft; LONGtop; LONGright; LONGbottom; } RECT;  Declaration (AFXWIN.H)

30 Class CRect (cont’d) void CRect::DeflateRect(LPCRECT lpRect) { left += lpRect->left; top += lpRect->top; right -= lpRect->right; bottom -= lpRect->bottom; }

31 MFC Collection Classes  MFC collection classes  Array 일반적인 C++ 에서의 array 임 일반적인 C++ 에서의 array 임 단 모든 메모리관련 기능 추가 단 모든 메모리관련 기능 추가  List Doubly linked list Doubly linked list  Map 일종의 dictionary 일종의 dictionary Key, value 쌍으로 데이터를 저장 Key, value 쌍으로 데이터를 저장

32 Type of Collection Classes  Template-based  Nontemplate-based  Array : CObArray, CByteArray, …  List : CObList, CPtrList, CStringList  Map : CMapPtrToWord, … Collection contents ArrayListMap Collections of objects of any type CArrayCListCmap Collections of pointers to objects of any type CTypedPtrArrayCTypedPtrListCTypedPtrMap

33 Shape Features ShapeOrdered?Indexed?InsertSearchDuplicate ListYesNoFastSlowYes ArrayYes By int SlowSlowYes MapNo By key FastFastNo(key)Yes(value)

34 Type-safe Collection  Template-based classes  변수 선언  멤버 함수 호출  필요할 경우, helper function 구현 (CArray, CList, CMap 에서 ) CompareElements CompareElements CopyElements CopyElements Dumpelements Dumpelements HashKey HashKey SerializeElements SerializeElements

35 Type-safe Collection (cont’d) // 변수 선언 CList m_intList; // 함수 호출 m_intList.AddTail( 100 ); m_intList.RemoveAll( ); // helper function 구현 class CPerson : public CObject {... }; CArray personArray; template <> void AFXAPI SerializeElements ( CArchive& ar, CPerson* pNewPersons, int nCount ) CPerson* pNewPersons, int nCount ){ for ( int i = 0; i < nCount; i++, pNewPersons++ ) for ( int i = 0; i < nCount; i++, pNewPersons++ ) { // Serialize each CPerson object // Serialize each CPerson object pNewPersons->Serialize( ar ); pNewPersons->Serialize( ar ); }}

36 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 );} void AddHeadPerson( CPerson* person ) {AddHead( person );} const CPerson* GetHeadPerson() {return (CPerson*)GetHead();} const CPerson* GetHeadPerson() {return (CPerson*)GetHead();}};

37 Iteration  Array  List CTypedPtrArray myArray; for( int i = 0; i < myArray.GetSize();i++ ){ CPerson* thePerson = myArray.GetAt( i ); CPerson* thePerson = myArray.GetAt( i ); // CPerson* thePerson = myArray[ i ]; // CPerson* thePerson = myArray[ i ];} CTypedPtrList myList; POSITION pos = myList.GetHeadPosition(); while( pos != NULL ) { CPerson* thePerson = myList.GetNext( pos ); CPerson* thePerson = myList.GetNext( pos );......}

38 Iteration (cont’d)  Map CMap myMap; POSITION pos = myMap.GetStartPosition(); while( pos != NULL ) { CPerson* pPerson; CPerson* pPerson; CString string; CString string; myMap.GetNextAssoc( pos, string, pPerson ); myMap.GetNextAssoc( pos, string, pPerson );} CMapStringToOb myMap; // A nontemplate collection class POSITION pos = myMap.GetStartPosition( ); while( pos != NULL ) { CPerson* pPerson; CPerson* pPerson; CString string; CString string; myMap.GetNextAssoc( pos, string, (CObject*&)pPerson ); myMap.GetNextAssoc( pos, string, (CObject*&)pPerson ); ASSERT( pPerson->IsKindOf( RUNTIME_CLASS( CPerson ) ) ); ASSERT( pPerson->IsKindOf( RUNTIME_CLASS( CPerson ) ) );}

39 Additional Structures  Stack class CTray : public CObject {... }; class CStack : public CTypedPtrList class CStack : public CTypedPtrList {public: // Add element to top of stack // Add element to top of stack void Push( CTray* newTray ) void Push( CTray* newTray ) { AddHead( newTray ); } { AddHead( newTray ); } // Peek at top element of stack // Peek at top element of stack CTray* Peek() CTray* Peek() { return IsEmpty() ? NULL : GetHead(); } { return IsEmpty() ? NULL : GetHead(); } // Pop top element off stack // Pop top element off stack CTray* Pop() CTray* Pop() { return RemoveHead(); } { return RemoveHead(); }};

40 Additional Structures (cont’d)  Queue class CPerson : public CObject {... }; class CQueue : public CTypedPtrList class CQueue : public CTypedPtrList {public: // Go to the end of the line // Go to the end of the line void AddToEnd( CPerson* newPerson ) void AddToEnd( CPerson* newPerson ) { AddTail( newPerson ); } // End of the queue { AddTail( newPerson ); } // End of the queue // Get first element in line // Get first element in line CPerson* GetFromFront() CPerson* GetFromFront() { return IsEmpty() ? NULL : RemoveHead(); } { return IsEmpty() ? NULL : RemoveHead(); }};

41 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);}

42 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);

43 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);

44 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; };

45 CWordArray Class (cont’d)  CWordArray(ARRAY_W.CPP)  멤버 변수 m_pData m_pData  저장된 데이터의 포인터 m_nSize m_nSize  Current size of array(“logical” size) m_nMaxSize m_nMaxSize  “Physical” size M_nGrowBy M_nGrowBy  추가 메모리 할당시 추가 할당 크기  SetSize() 를 통한 이해

46 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; }

47 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 elsenNewMax = nNewSize; // no slush WORD* pNewData = (WORD*) new BYTE[nNewMax * sizeof(WORD)];

48 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; }

49  SetSize()(ARRAY_W.CPP)  5 개의 section 으로 구성 Initialization section Initialization section Shrink-to-nothing section Shrink-to-nothing section First allocation section First allocation section Allocate-from-extra-space section Allocate-from-extra-space section Grow-the-array section Grow-the-array section CWordArray Class (cont’d)

50  SetAt()(AFXCOLL.INL)  m_pData[nIndex] = newElement;  InsertAt()(ARRAY_W.CPP)  Array 마지막에 insert 하는 경우 메모리 할당 후 insert 메모리 할당 후 insert  Array 중간에 insert 하는 경우 메모리 할당 후 데이터 이동작업 메모리 할당 후 데이터 이동작업 Expensive  무분별한 사용을 삼가 Expensive  무분별한 사용을 삼가 CWordArray Class (cont’d)

51 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; }

52  GetAt() and operator[] (AFXCOLL.INL)  많은 데이터 access 함수가 GetAt() 을 내부적으로 호출 내부 구현 변경시 GetAt() 만 수정하면 됨 내부 구현 변경시 GetAt() 만 수정하면 됨 Data abstraction 기술을 배울만함 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); } CWordArray Class (cont’d)

53 List Collections  List collections  CObList, CPtrList, CStringList  Doubly linked list  Supporting operator as follows AddHead(), Find(), GetCount() AddHead(), Find(), GetCount() GetHEad(), GetNext(), GetTail(), IsEmpty() GetHEad(), GetNext(), GetTail(), IsEmpty() RemoveAll(), RemoveHead(), RemoveTail() RemoveAll(), RemoveHead(), RemoveTail() InsertAfter(), InsertBefore() InsertAfter(), InsertBefore() POSITION pos = m_strList.GetHeadPositon(); while ( pos != NULL ) CString tmpString = m_strList.GetNext(pos);

54 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();

55 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);

56 CStringList Class (cont’d) POSITION InsertBefore(POSITION position, LPCTSTR newElement); POSITION InsertAfter(POSITION position, LPCTSTR newElement); POSITION InsertBefore(POSITION position, const CString& newElement); POSITION InsertAfter(POSITION position, const CString& newElement); POSITION Find(LPCTSTR searchValue, POSITION startAfter = NULL) const; POSITION 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; };

57  CStringList(AFXCOLL.H)  멤버 CNode structure CNode structure  실제 list 에서의 한 node 를 위한 structure m_pNodeHead m_pNodeHead  List 에서의 처음 element 에 대한 node pointer m_pNodeTail m_pNodeTail  List 에서의 마지막 element 에 대한 node pointer m_nCount m_nCount  List 에서의 element 의 수 CStringList Class (cont’d)

58  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 }; CStringList Class (cont’d)

59  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; } CStringList Class (cont’d)

60 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; } CStringList Class (cont’d)

61  CStringList::NewNode()(LIST_S.CPP)  CStringList 의 memory 관리의 핵심  Add(), Insert() 등의 함수가 위 함수를 내부적으로 이용  MFC list 는 free CNode element 로 이루어진 singly linked list 를 유지하고 있다.(m_pNodeFree)  Free node 가 없으면 CPlex::Create() 함수를 이용하여 메모리 할당 CPlex::Create() 함수를 이용하여 메모리 할당 할당된 메모리를 list 형태로 변환 후 head 를 m_pNodeFree 가 가리키게 함 할당된 메모리를 list 형태로 변환 후 head 를 m_pNodeFree 가 가리키게 함  POSITION  내부적으로 CNode 에 대한 pointer 역할 CStringList Class (cont’d)

62 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; } CStringList Class (cont’d)

63  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; } CStringList Class (cont’d)

64  List memory 관리 요약  세개의 list 를 관리한다. Actual in-use list Actual in-use list  Doubly linked list of CNodes  m_pNodeHead, m_pNodeTail List of free nodes List of free nodes  Singly linked list of CNodes(m_pNodeFree) All allocated memory blocks All allocated memory blocks  Singly linked list of CPlexes(m_pBlocks) CStringList Class (cont’d)

65 Map Collections  Map collections  CMapPtrToPtr, CMapStringToOb  CMapStringToPtr, CMapStringToString  CMapWordToOb, CMapWordToPtr  특징  Dictionary 라고 불리기도 함  Key, value 쌍을 하나의 단위 (association) 로 저장함  Hash table 을 이용함

66  예제 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); … }

67 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);

68 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; };

69  CMapWordToPtr(AFXCOLL.H)  멤버 CAssoc structure CAssoc structure  Map 의 element 를 나타내는 structure  Memory management List 와 동일 (CPlex 이용 ) List 와 동일 (CPlex 이용 )  Map Hashing 내부적으로 hash table 을 생성 (Array of CAssoc pointer) 내부적으로 hash table 을 생성 (Array of CAssoc pointer) InitHashTable()(MAP_WP.CPP) InitHashTable()(MAP_WP.CPP) m_pHashTable, m_nHashTableSize m_pHashTable, m_nHashTableSize Map Collections (cont’d)

70 Word 와 string 에 대한 각각의 hash function 이 존재 (HashKey() 함수 ) Word 와 string 에 대한 각각의 hash function 이 존재 (HashKey() 함수 ) Collision 의 해결 Collision 의 해결  Linked list of collided items  CAssoc 의 pNext 멤버 변수 거의 모든 insert 는 operator[] 를 이용한다. 거의 모든 insert 는 operator[] 를 이용한다. operator[] operator[]  Collision 해결 코드가 들어가 있다. _AFXCOLL_INLINE void CMapWordToPtr::SetAt(WORD key, void* newValue) { (*this)[key] = newValue; } Map Collections (cont’d)

71 CFile Class Family  CFile class family  CFile Nonbuffered file access (Windows API) Nonbuffered file access (Windows API)  CStdioFile Buffered I/O 로 CFile 을 발전시킴 Buffered I/O 로 CFile 을 발전시킴  CMemFile, CSharedFile Shared memory 를 CFile interface 로 구현 Shared memory 를 CFile interface 로 구현

72 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);

73 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);

74 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; };

75  Declaration of CFile(AFX.H)  멤버 m_hFile m_hFile  Windows file handle BufferCommand, GetBufferPtr() BufferCommand, GetBufferPtr()  CMemFile 의 기능을 위한 멤버 m_bCloseOnDelete m_bCloseOnDelete  CFile object 가 destroy 될 때 file handle 을 close 할 지를 나타냄 m_strFileName m_strFileName  File name CFile Class (cont’d)

76  Operations 거의 모든 operator 들이 window API 를 내부적으로 그대로 호출하는 수준 거의 모든 operator 들이 window API 를 내부적으로 그대로 호출하는 수준 Open()  ::Createfile() Open()  ::Createfile() Read()  ::ReadFile() Read()  ::ReadFile() Write()  ::WriteFile() Write()  ::WriteFile() CFile Class (cont’d)

77 CFile Operation (cont’d)  Opening  Reading & Writing 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 ); } char szBuffer[256]; UINT nActual = 0; CFile myFile; myFile.Write( szBuffer, sizeof( szBuffer ) ); myFile.Seek( 0, CFile::begin ); nActual = myFile.Read( szBuffer, sizeof( szBuffer ) );

78 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 ); }

79 CStdioFile  CFile 과의 차이점  Wrapping C run-time library(fopen,…)  Buffered I/O  ReadString() 과 WriteString() 함수 지원 Text mode 로 파일을 열면 string 의 read/write 를 지원 Text mode 로 파일을 열면 string 의 read/write 를 지원  Buffering 지원으로 인해 몇 개의 function 은 쓸 수 없다.

80 CStdioFile(contd.)  Declaration of CStdioFile(AFX.H)  멤버 m_pStream m_pStream  FILE pointer ReadString(), WriteString()(FILETXT.CPP) 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; }

81 CMemFile  존재 이유  MFC 의 serialization 기능을 memory 에 이용하기 위해  Declaration of CMemFile(AFX.H)  멤버 m_nGrowBytes m_nGrowBytes  내부 buffer 의 증가 단위 m_nPosition m_nPosition  Memory block 에서의 file pointer

82 CMemFile(contd.) m_nBufferSize m_nBufferSize  Buffer 의 크기 m_nFileSize m_nFileSize  Logical memory file 의 크기  m_nFileSize <= m_nBufferSize m_nlpBuffer m_nlpBuffer  Buffer 에 대한 pointer m_bAutoDelete m_bAutoDelete  Destructor 가 호출될 때 memory 를 free 할 건지를 나타냄

83 CMemFile(contd.)  Memory handling CArray memory handling 과 유사 CArray memory handling 과 유사 GrowFile()(FILEMEM.CPP) GrowFile()(FILEMEM.CPP)  Memory 할당의 단위는 m_nGrowBytes 크기  이미 할당되어 있으면 realloc Read()(FILEMEM.CPP) Read()(FILEMEM.CPP)  지정한 크기 만큼 buffer 에서 읽어서 넘겨줌  File 에 대한 작업과 interface 는 동일

84 CSharedFile  특징  CMemFile 에서 상속을 받음  Windows global memory API 를 사용 GlobalAlloc(), GlobalReAlloc(), … GlobalAlloc(), GlobalReAlloc(), …  OLE 기능 구현에 이용됨  AFXPRIV.H

85 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  …

86 CException  Declaration of CException(AFX.H)  멤버 GetErrorMessage() GetErrorMessage()  Exception 에 해당하는 message string 을 가져옴 ReportError() ReportError()  Message 출력  예 :CFileException(AFX.H)  가능한 exception 을 enumeration type 으로 가지고 있다.

87 CException(contd.)  Exception 발생시 AfxThrowFileException() 함수를 호출  AfxThrowFileException()(FILEX.CPP) 적절한 처리후 throw 함 적절한 처리후 throw 함  해당 catch 내부의 문이 수행됨  멤버 m_cause m_cause  Enumerated Cfile exception m_strFileName m_strFileName  Exception 을 발생시킨 file name

88 CException(contd.) // … CMemFile myMemFile; try { // … myMemFile.Seek(2043); // … } catch (CFileException, e) { if (e->m_cause == CFileException::badSeek) … e->Delete(); } END_CATCH

89 Chap. 5 CObject Class

90 Contents  Introduction  CObject features  RTCI  Dynamic creation  Persistence  Diagnostics

91 Introduction  CObject Class  대부분의 MFC class 들의 최상위 부모 class singly rooted hierarchy singly rooted hierarchy  대부분의 MFC class 들에게 필요한 기능 구현  문제점 가상 테이블의 거대화와 성능 저하 가상 테이블의 거대화와 성능 저하 Poor object-oriented design Poor object-oriented design

92 CObject Features  Run-time class information (RTCI)  Dynamic creation  Persistence (serialization)  Diagnostic support

93 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();

94 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(); };

95 Macro  DECLARE macro  Class 에 멤버 변수와 함수를 선언  Header(Interface) file 에 존재  IMPLEMENT macro  Class 의 멤버 변수와 함수를 구현  C++ file 에 존재  종류  DECLARE_DYNAMIC / IMPLEMENT_DYNAMIC  DECLARE_DYNCREATE / IMPLEMENT_DYNCREATE  DECLARE_SERIAL / IMPLEMENT_SERIAL

96 Macro (cont’d)  세 Macro 의 포함 관계 RTCI Dynamic Creation Serialization “DYNAMIC” OXX “DYNCREATE” OOX “SERIAL” OOO

97 Run-Time Class Information (RTCI)  정의  개발자는 어떤 object 의 class name, parent 같은 정보를 run time 에 알 수 있다.  Run-Time Type Information (RTTI)  C++ language 의 특성  RTCI 와 동일한 기능  향후 통합 가능성

98 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; }

99 RTCI 과정  AFX.H #define DECLARE_DYNAMIC(class_name) \ public: \ static const AFX_DATA CRuntimeClass class##class_name; \ virtual CRuntimeClass* GetRuntimeClass() const; \ public: static const AFX_DATA CRuntimeClass classCMyClass; virtual CRuntimeClass* GetRuntimeClass() const; Preprocessor Class_name : CMyClass

100 RTCI 과정 (cont’d) #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 }; \ CRuntimeClass* class_name::GetRuntimeClass() const \ { return RUNTIME_CLASS(class_name); } \ #define RUNTIME_CLASS(class_name) ((CRuntimeClass*)(&class_name::class##class_name))

101 AFX_COMDAT const AFX_DATADEF CRuntimeClass CMyClass::classCMyClass = { “ CMyClass ”, sizeof(CMyClass), 0xFFFF, NULL, &CObject::classCObject, NULL }; CRunTimeClass* CMyClass::GetRuntimeClass() const { return &CMyClass::classCMyClass; } RTCI 과정 (cont’d) m_lpszClassName = “CMyClass” m_nObjectSize= sizeof(CMyClass) m_wSchema= 0xFFFF m_pfnCreateObject= NULL m_pBaseClass= RUNTIME_CLASS(CObject)

102 CRuntimeClass  AFX.H struct CRuntimeClass { // Attributes LPCSTR m_lpszClassName; LPCSTR m_lpszClassName; int m_nObjectSize; int m_nObjectSize; UINT m_wSchema; // schema number of the loaded class UINT m_wSchema; // schema number of the loaded class CObject* (PASCAL* m_pfnCreateObject)(); // NULL=>abstract class CObject* (PASCAL* m_pfnCreateObject)(); // NULL=>abstract class CRuntimeClass* m_pBaseClass; CRuntimeClass* m_pBaseClass; // Operations CObject* CreateObject(); CObject* CreateObject(); BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const; BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const; // Implementation void Store(CArchive& ar) const; void Store(CArchive& ar) const; CRuntimeClass* m_pNextClass; // linked list of registered classes CRuntimeClass* m_pNextClass; // linked list of registered classes};

103 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); }

104 CRuntimeClass::IsDerivedFrom()  OBJCORE.CPP BOOL CRuntimeClass::IsDerivedFrom(const CRuntimeClass* pBaseClass) const { // simple SI case const CRuntimeClass* pClassThis = this; while (pClassThis != NULL) { if (pClassThis == pBaseClass) return TRUE; pClassThis = pClassThis->m_pBaseClass; } return FALSE; // walked to the top, no match }

105 Dynamic Creation  Object 의 동적 생성  CRuntimeClass 의 정보를 가지고 object 를 동적으로 생성할 수 있다.(CreateObject())  RTCI macro  DECLARE_DYNCREATE IMPLEMENT_DYNCREATE DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC 보다 상위에 있는 macro DECLARE_DYNAMIC/IMPLEMENT_DYNAMIC 보다 상위에 있는 macro 따라서 위 macro 는 자동 포함됨 따라서 위 macro 는 자동 포함됨

106 Dynamic Creation 사용 예  CMyClass 가 DYNCREATE macro 를 사용 CRuntimeClass* pRuntimeClass = RUNTIME_CLASS(CMyClass); Cobject* pObject = pRuntimeClass->CreateObject(); ASSERT(pObject->IsKindOf(RUNTIME_CLASS(CMyClass))); pDocTemplate = new CMultiDocTemplate(IDR_SCRIBTYPE, RUNTIME_CLASS(CScribDoc), RUNTIME_CLASS(CMDIChildWnd), RUNTIME_CLASS(CScribView));

107 Dynamic Creation 과정  AFX.H #define DECLARE_DYNCREATE(class_name) \ DECLARE_DYNAMIC(class_name) \ static CObject* PASCAL CreateObject(); public: static const AFX_DATA CRuntimeClass classCMyClass; virtual CRuntimeClass* GetRuntimeClass() const; static CObject* PASCAL CreateObject(); Preprocessor Class_name : CMyClass

108 Dynamic Creation 과정 (cont’d) #define IMPLEMENT_DYNCREATE(class_name, base_class_name) \ CObject* PASCAL class_name::CreateObject() \ { return new class_name; } \ IMPLEMENT_RUNTIMECLASS(class_name, base_class_name, 0xFFFF, \ class_name::CreateObject) m_lpszClassName = “CMyClass” m_nObjectSize= sizeof(CMyClass) m_wSchema= 0xFFFF m_pfnCreateObject= CMyClass::CreateObject m_pBaseClass= RUNTIME_CLASS(CObject)

109 CRuntimeClass::CreateObject()  OBJCORE.CPP CObject* CRuntimeClass::CreateObject() { if (m_pfnCreateObject == NULL) return NULL; CObject* pObject = NULL; TRY { pObject = (*m_pfnCreateObject)(); } END_TRY return pObject; }

110 Persistence  Persistence 란 ?  Object 의 state 정보를 저장 (store) 했다가 나중에 복원 (recover) 할 수 있는 능력  MFC 에서 말하는 serialization  Format 에 신경쓰지 않고 object 자체를 파일에 읽고 쓸 수 있게 한다. 모든 일은 내부적으로 처리됨 모든 일은 내부적으로 처리됨  관련 멤버함수 IsSerializable() IsSerializable() Serialize() Serialize()

111 Serialization 의 지원  다음의 두 가지 작업  DECLARE_SERIAL / IMPLEMENT_SERIAL macro 를 이용한다. 이 때, schema( 버전 정보 ) 를 반드시 넣는다.  CObject::Serialize() 함수를 override 한다. 자신의 class data member 에 맞게 자신의 class data member 에 맞게

112 Serialization 예 // Header file class CMyClass : public CObject { DECLARE_SERIAL(CMyClass) public: CMyClass(); WORD m_wType; DWORD m_dwData; CPoint m_ptMiddle; void Serialize(CArchive &); }

113 Serialization 예 (cont’d) // 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; }

114 CArchive Class  AFX.H  목적  Binary stream ( not ASCII stream )  Tied to CFile pointer  Implementing buffering of data

115 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);

116 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);

117 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);

118 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;

119 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; CMapPtrToPtr* m_pStoreMap; }; // map to keep track of mismatched schemas CMapPtrToPtr* m_pSchemaMap; // advanced parameters (controls performance with large archives) UINT m_nGrowSize; UINT m_nHashSize; };

120 CArchive Class (cont’d)  Members  m_nMode 읽기인지 쓰기인지 결정 읽기인지 쓰기인지 결정  IsLoading(), IsStoring(), IsByteSwapping(), IsBufferEmpty() CArchive object 의 state access 함수 CArchive object 의 state access 함수

121 CArchive Class (cont’d)  Operators CObject, Windows data type, C++ data type 에 대한 insertion, extraction operator CObject, Windows data type, C++ data type 에 대한 insertion, extraction operator  Class member functions WriteClass(), ReadClass(), SerializeClass() WriteClass(), ReadClass(), SerializeClass() CRuntimeClass structure 의 정보를 읽고 쓰기 위한 함수 CRuntimeClass structure 의 정보를 읽고 쓰기 위한 함수  Map members 이미 저장되었거나 읽혀진 object 의 정보를 빠르게 얻기 위한 mapping 정보 관리 이미 저장되었거나 읽혀진 object 의 정보를 빠르게 얻기 위한 mapping 정보 관리

122 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; }

123 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);

124 Serialization 과정 (cont’d) #define IMPLEMENT_SERIAL(class_name, base_class_name, wSchema) \ CObject* PASCAL class_name::CreateObject() \ { 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; } \ CArchive& AFXAPI operator>>(CArchive& ar, CMyClass* &pOb) { pOb = (CMyClass*)ar.ReadObject(RUNTIME_CLASS(CMyClass)); return ar; } Preprocessor Class_name : CMyClass

125 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; }

126 Serialization 과정 (cont’d)  Macro 에 insertion operator 가 없는 이유  Global insertion operator 가 존재함 (AFX.INL)  특별히 CRuntimeClass 정보를 필요로 하지 않기 때문 CObject 에 대한 insertion operator 로 충분함 CObject 에 대한 insertion operator 로 충분함 _AFX_INLINE CArchive& AFXAPI operator<<(CArchive& ar, const CObject* pOb) { ar.WriteObject(pOb); return ar; }

127 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); }}

128 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 */ }

129 Read & Write 추적  목적 및 가정  Serialization 의 진행 과정 이해  Document/View architecture 가정  우리의 document class 가 다음의 멤버 변수를 가짐 CMyClass* m_pMyClass; CMyClass* m_pMyClass; class CMyClass : public CObject { DECLARE_SERIAL(CMyClass) public: CMyClass(); WORD m_wType; DWORD m_dwData; CPoint m_ptMiddle; void Serialize(CArchive &); }

130 Read & Write 추적 (cont’d) void CMyDocument::Serialize(CArchive& ar) { if (ar.IsStoring()) { ar << m_pMyClass; } else { ar >> m_pMyClass; }

131 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;

132 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; }

133 Read 과정 (cont’d) 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; }

134 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; }

135 Read 과정 (cont’d) “ AFXWIN1.INL ” _AFXWIN_INLINE CArchive& AFXAPI operator>>(CArchive& ar, POINT& point) { ar.Read(&point, sizeof(POINT)); return ar; }

136 Store Operation  Write case CDocument::OnSaveDocument() operator<<(CArchive&, CObject*) CArchive::CArchive() CMyDocument::Serialize() CArchive::IsStoring() CArchive::WriteObject() CArchive::WriteClass() CMyClass::Serialize() operator<<(CArchive&, point) CArchive::IsStoring() CArchive::operator<<(WORD) CArchive::operator<<(DWORD) CArchive::Write() CArchive::Close()

137 Read Operation  Read case CDocument::OnOpenDocument() operator>>(CArchive&, CMyClass*) CArchive::CArchive() CMyDocument::Serialize() CArchive::IsStoring() CArchive::ReadObject() CMyClass::Serialize() Operator>>(CArchive&, point) CArchive::IsStoring() CArchive::operator>>(WORD) CArchive::operator>>(DWORD) CArchive::Read() CArchive::Close() CArchive::WriteClass()

138 Serialization Performance  Data structure  Maps and arrays  어떤 type 의 데이터를 여러 번 읽고 쓰는 경우 그 때마다 class 정보를 읽고 쓰는 것은 비효율적  Write Map : reference no. + class name Map : reference no. + class name MFC 는 reference no. 만 write MFC 는 reference no. 만 write  Read Array : CArchive 는 array 를 유지하며 reference no. 를 decoding 하여 해당 class 정보를 획득 Array : CArchive 는 array 를 유지하며 reference no. 를 decoding 하여 해당 class 정보를 획득  Serializing large data  SetLoadParam(), SetStoreParam()  Storing map 의 hash table size 나 reading array 의 grow-by size 조절

139 CRuntimeClass member 저장  State serialization  LPCSTR m_lpszClassName Class 의 이름 Class 의 이름  UINT m_wSchema Class version 정보 Class version 정보  Store() CRuntimeClass 의 state 를 실제 저장하는 함수 CRuntimeClass 의 state 를 실제 저장하는 함수  Load() CRuntimeClass 의 state 를 실제 읽어 들이는 함수 CRuntimeClass 의 state 를 실제 읽어 들이는 함수  m_nObjectSize, m_pNextClass debugging 을 위해 필요 debugging 을 위해 필요 AfxAssertValidObject(), AfxDoForAllClasses() AfxAssertValidObject(), AfxDoForAllClasses()

140 CObject Diagnostic Support  크게 2 가지로 분류됨  Basic diagnostics Diagnostic output Diagnostic output  TRACE macro  Dump() Run-time checking Run-time checking  ASSERT macro  AssertValid()  ASSERT_VALID macro  Advanced memory diagnostics Memory leak detection Memory leak detection Memory statistics Memory statistics

141 Enabling Diagnostics  AfxEnableMemoryTracking  Debug 모드에서는 diagnostic 이 적용된다.  그러나, 임시로 조절 가능 BOOL CWinMyApp::InitInstance() { #ifdef _DEBUG #ifdef _DEBUG // Disable tracking of memory for the scope of the InitInstance() // Disable tracking of memory for the scope of the InitInstance() AfxEnableMemoryTracking(FALSE); AfxEnableMemoryTracking(FALSE); #endif // _DEBUG #endif // _DEBUG #ifdef _DEBUG #ifdef _DEBUG // Re-enable tracking of memory // Re-enable tracking of memory AfxEnableMemoryTracking(TRUE); AfxEnableMemoryTracking(TRUE); #endif // _DEBUG #endif // _DEBUG}

142 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);

143 Inside TRACE  TRACE(AFX.H)  단순히 AfxTrace() 라는 전역함수를 부름 #define TRACE ::AfxTrace  AfxTrace()(DUMPOUT.CPP) afxDump 를 이용 afxDump 를 이용

144 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 m_pszExeName m_pszExeName << ": "; afxDump << szBuffer; va_end(args);}

145 Inside TRACE (cont’d)  afxDump(AFX.H)  CDumpContext 의 global instance  최종적으로 CDumpContext 의 OutputString() (DUMPCONT.CPP) 가 출력 담당  특정 파일에 출력도 가능 #ifdef _DEBUG extern AFX_DATA CDumpContex afxDump; #endif

146 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)); }

147 Diagnostic Output – Dump()  Object dump  CObject 의 하위 클래스들이 가진 멤버함수  클래스의 state 를 print 하기 위해 호출  Debug build 에서만 유효  예 )

148 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

149 Inside Dump()  Object dumping(OBJCORE.CPP) #ifdef _DEBUG void CObject::Dump(CDumpContext& dc) const { dc m_lpszClassName << " at " << (void*)this << "\n"; } #endif //_DEBUG 단지 class 이름과 주소만 출력

150 Run-Time Checking - ASSERT  Assertions  ASSERT macro  Run-time 시의 어떤 상태를 체크하고 실패하면 warning message box 가 나타난다.  MFC 도 5000 개 이상의 ASSERT 문을 포함 (VC++ 4)  사용 권유 예 ) window handle 이 유효한지 미리 체크 예 ) 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*.

151 Inside ASSERT #define ASSERT(f) \ do \ { \ if (!(f) && AfxAssertFailedLine(THIS_FILE, __LINE__)) \ AfxDebugBreak(); \ } while (0) \

152 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

153 Inside AssertValid() void CObject::AssertValid() const { ASSERT(this != NULL); }

154 Run-Time Checking – ASSERT_VALID  ASSERT_VALID macro  CObject 의 하위 클래스에 대해 호출 가능  AssertValid() 에 대한 호출 + 부가적인 체크  예를 들어 document class 가 CMyClass 멤버변수를 가지면 다음과 같이 체크할 수 있다. CMyDocument::AssertValid(){…ASSERT_VALID(m_myClass);…}

155 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 (pOb == NULL) { if (AfxAssertFailedLine(lpszFileName, nLine)) AfxDebugBreak(); return; // quick escape } if (!AfxIsValidAddress(pOb, sizeof(CObject))) // … if (!AfxIsValidAddress(pOb, sizeof(CObject))) // … if (!AfxIsValidAddress(*(void**)pOb, sizeof(void*), FALSE)) // … if (!AfxIsValidAddress(*(void**)pOb, sizeof(void*), FALSE)) // … if (!AfxIsValidAddress(pOb, pOb->GetRuntimeClass()->m_nObjectSize, if (!AfxIsValidAddress(pOb, pOb->GetRuntimeClass()->m_nObjectSize, FALSE)) // … FALSE)) // … pOb->AssertValid(); pOb->AssertValid();}

156 Detect a Memory Leak  Memory leak  Heap 에 할당된 영역을 다시 deallocate 하지 않을 때  할당된 메모리 영역을 이용하려 할 때  발견하기 무척 어려움 #ifdef _DEBUG CMemoryState startMemState, stopMemState, diffMemState; startMemState.Checkpoint(); #endif _DEBUG Cstringabc = “ Free me! ” ; // … #ifdef _DEBUG stopMemState.Checkpoint(); if ( diffMemState.Difference(startMemState, stopMemState)) { TRACE( “ Memory leak! ” ); } #endif _DEBUG

157 Specific Memory Diagnostic  afxMemDF  memory diagnostic 의 기능을 선택적으로 하기 위한 global variable  value allocMemDF : Turn on memory allocator (default) allocMemDF : Turn on memory allocator (default) delayFreeMemDF : 프로그램이 종료할 때까지 메모리를 free 하지 않음. 이를 통해 프로그램이 최대로 할당 받을 수 있는 메모리 체크 가능. delayFreeMemDF : 프로그램이 종료할 때까지 메모리를 free 하지 않음. 이를 통해 프로그램이 최대로 할당 받을 수 있는 메모리 체크 가능. checkAlwaysMemDF : 메모리가 allocate 되거나 free 될 때마다 메모리 상태 체크 (AfxCheckMemory 호출 ) checkAlwaysMemDF : 메모리가 allocate 되거나 free 될 때마다 메모리 상태 체크 (AfxCheckMemory 호출 ) AfxMemDF = allocMemDF | delayFreeMemDF | checkAlwaysMemDF;

158 Review Memory Statics  CMemoryState class  DumpStatistics() delay 된 메모리의 양 delay 된 메모리의 양 heap 에 남아 있는 양 heap 에 남아 있는 양 program 에 필요한 메모리 양 등등 … program 에 필요한 메모리 양 등등 …  DumpAllObjectsSince() 지금까지 할당된 모든 object 들의 기록 표시 지금까지 할당된 모든 object 들의 기록 표시 가장 최근의 CMemoryState::Checkpoint() 부터 기록 가장 최근의 CMemoryState::Checkpoint() 부터 기록

159 예 // 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", " " ); if( diffMemState.Difference( oldMemState, newMemState ) ) { TRACE( "Memory leaked!\n" ); TRACE( "Memory leaked!\n" ); diffMemState.DumpAllObjectsSince(); 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 #: {1} strcore.cpp(80) : non-object block at $00A7516E, 25 bytes long

160 Inside Memory Diagnostics  CMemoryState class  AFX.H  모든 memory allocation 에 대한 개수와 크기 정보를 가지고 있다. new operator 를 override 함으로 인해서 가능 new operator 를 override 함으로 인해서 가능  Debugging 상태에서는 new 를 DEBUG_NEW 로 대체함 #ifdef _DEBUG #define new DEBUG_NEW #endif //_DEBUG

161 Inside Memory Diagnostics (cont’d)  AFX.H  DEBUG_NEW declaration 파일 이름과 라인을 저장함 파일 이름과 라인을 저장함  Global new operator  CObject::operator new 또 다른 debug new operator 또 다른 debug new operator 객체인지 체크 객체인지 체크 내부적으로 호출하는 AfxAllocMemoryDebug() 함수의 argument 차이 내부적으로 호출하는 AfxAllocMemoryDebug() 함수의 argument 차이 #define DEBUG_NEW new(THIS_FILE, __LINE__) void* operator new(size_t, nSize, PCSTR lpszFileName, int nLine)

162  AfxAllocMemoryDebug() (AFXMEM.CPP) Malloc(sizeof(CBlockHeader) + nSize + nNoMansLandSize); Malloc(sizeof(CBlockHeader) + nSize + nNoMansLandSize); CBlockHeader 부분에 debugging 시 필요한 모든 정보를 저장함 CBlockHeader 부분에 debugging 시 필요한 모든 정보를 저장함 No mans land 부분에 overwrite 체크를 위한 정보를 저장함 No mans land 부분에 overwrite 체크를 위한 정보를 저장함 할당하는 모든 메모리 block 들을 리스트로 연결 할당하는 모든 메모리 block 들을 리스트로 연결 Advanced memory…(contd.) CBlockHeaderGap 데이터를 위한 부분 No Mans Land


Download ppt "Chap. 4 Utility Classes. Contents  Simple value types  일반적 목적 : CString, CTime, CTimeSpan  윈도우 구조체 : CPoint, CSize, Crect  MFC collection classes."

Similar presentations


Ads by Google