델파이의 TList는 C의 void* 형 컨테이너라고 생각하시면 됩니다.
델파이나 C 모두 타입, 예외 안전은 제공하지 못하므로 어쩔 수 없이 이런 방식으로 사용해야 하고, 삽입되는 메모리의 해제는 (만약 할당한 메모리라면) 프로그래머의 책임입니다. (물론 TObjectList 같은 것은 자체적인 Free를 수행해주기도 합니다만 이건 예외적인 것이겠죠.)
C++ 에서는 여러가지가 있겠지만 평범한 :wink: 해결책으로는 STL의 컨테이너를 사용하고 boost::shared_ptr 을 사용해서 여러가지 잇점을 얻을 수 있을 것입니다.
제생각에도 stl 쓰는것이 좋은 방법이라 생각되고요,
템플릿을 사용하지 않고, void* 형으로 사용하고 싶으시면,
MFC 에 CPtrList 라고 있습니다. 물론 윈도우용이고요
이걸 쪼금 고쳐서 리눅스용으로 만들어 봤습니다.
참고로, 검증이 안된 코드입니다.
PtrList.cpp
#include "afx.h" // <-- 여기엔 공통적으로 쓰이는 헤더화일을 적당히 넣어줍니다.
#include "PtrList.h"
CPlex* CPlex::Create(CPlex*& pHead, unsigned int nMax, unsigned int cbElement)
{
CPlex* p = (CPlex*) new unsigned char[sizeof(CPlex) + nMax * cbElement];
// may throw exception
p->pNext = pHead;
pHead = p; // change head (adds in reverse order for simplicity)
return p;
}
void CPlex::FreeDataChain() // free this one and links
{
CPlex* p = this;
while (p != NULL)
{
unsigned char* bytes = (unsigned char*) p;
CPlex* pNext = p->pNext;
delete[] bytes;
p = pNext;
}
}
CPtrList::CPtrList(int nBlockSize)
{
m_nCount = 0;
m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
m_nBlockSize = nBlockSize;
}
CPtrList::~CPtrList()
{
RemoveAll();
}
void CPtrList::RemoveAll()
{
m_nCount = 0;
m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
}
CPtrList::CNode*
CPtrList::NewNode(CPtrList::CNode* pPrev, CPtrList::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;
}
}
CPtrList::CNode* pNode = m_pNodeFree;
m_pNodeFree = m_pNodeFree->pNext;
pNode->pPrev = pPrev;
pNode->pNext = pNext;
m_nCount++;
pNode->data = 0; // start with zero
return pNode;
}
void CPtrList::FreeNode(CPtrList::CNode* pNode)
{
pNode->pNext = m_pNodeFree;
m_pNodeFree = pNode;
m_nCount--;
if (m_nCount == 0)
RemoveAll();
}
/////////////////////////////////////////////////////////////////////////////
POSITION CPtrList::AddHead(void* newElement)
{
CNode* pNewNode = NewNode(NULL, m_pNodeHead);
pNewNode->data = newElement;
if (m_pNodeHead != NULL)
m_pNodeHead->pPrev = pNewNode;
else
m_pNodeTail = pNewNode;
m_pNodeHead = pNewNode;
return (POSITION) pNewNode;
}
POSITION CPtrList::AddTail(void* newElement)
{
CNode* pNewNode = NewNode(m_pNodeTail, NULL);
pNewNode->data = newElement;
if (m_pNodeTail != NULL)
m_pNodeTail->pNext = pNewNode;
else
m_pNodeHead = pNewNode;
m_pNodeTail = pNewNode;
return (POSITION) pNewNode;
}
void CPtrList::AddHead(CPtrList* pNewList)
{
POSITION pos = pNewList->GetTailPosition();
while (pos != NULL)
AddHead(pNewList->GetPrev(pos));
}
void CPtrList::AddTail(CPtrList* pNewList)
{
POSITION pos = pNewList->GetHeadPosition();
while (pos != NULL)
AddTail(pNewList->GetNext(pos));
}
void* CPtrList::RemoveHead()
{
CNode* pOldNode = m_pNodeHead;
void* returnValue = pOldNode->data;
m_pNodeHead = pOldNode->pNext;
if (m_pNodeHead != NULL)
m_pNodeHead->pPrev = NULL;
else
m_pNodeTail = NULL;
FreeNode(pOldNode);
return returnValue;
}
void* CPtrList::RemoveTail()
{
CNode* pOldNode = m_pNodeTail;
void* returnValue = pOldNode->data;
m_pNodeTail = pOldNode->pPrev;
if (m_pNodeTail != NULL)
m_pNodeTail->pNext = NULL;
else
m_pNodeHead = NULL;
FreeNode(pOldNode);
return returnValue;
}
POSITION CPtrList::InsertBefore(POSITION position, void* newElement)
{
if (position == NULL)
return AddHead(newElement); // insert before nothing -> head of the list
CNode* pOldNode = (CNode*) position;
CNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode);
pNewNode->data = newElement;
if (pOldNode->pPrev != NULL)
{
pOldNode->pPrev->pNext = pNewNode;
}
else
{
m_pNodeHead = pNewNode;
}
pOldNode->pPrev = pNewNode;
return (POSITION) pNewNode;
}
POSITION CPtrList::InsertAfter(POSITION position, void* newElement)
{
if (position == NULL)
return AddTail(newElement); // insert after nothing -> tail of the list
CNode* pOldNode = (CNode*) position;
CNode* pNewNode = NewNode(pOldNode, pOldNode->pNext);
pNewNode->data = newElement;
if (pOldNode->pNext != NULL)
{
pOldNode->pNext->pPrev = pNewNode;
}
else
{
m_pNodeTail = pNewNode;
}
pOldNode->pNext = pNewNode;
return (POSITION) pNewNode;
}
void CPtrList::RemoveAt(POSITION position)
{
CNode* pOldNode = (CNode*) position;
if (pOldNode == m_pNodeHead)
{
m_pNodeHead = pOldNode->pNext;
}
else
{
pOldNode->pPrev->pNext = pOldNode->pNext;
}
if (pOldNode == m_pNodeTail)
{
m_pNodeTail = pOldNode->pPrev;
}
else
{
pOldNode->pNext->pPrev = pOldNode->pPrev;
}
FreeNode(pOldNode);
}
POSITION CPtrList::FindIndex(int nIndex) const
{
if (nIndex >= m_nCount || nIndex < 0)
return NULL; // went too far
CNode* pNode = m_pNodeHead;
while (nIndex--)
{
pNode = pNode->pNext;
}
return (POSITION) pNode;
}
POSITION CPtrList::Find(void* searchValue, POSITION startAfter) const
{
CNode* pNode = (CNode*) startAfter;
if (pNode == NULL)
{
pNode = m_pNodeHead; // start at head
}
else
{
pNode = pNode->pNext; // start after the one specified
}
for (; pNode != NULL; pNode = pNode->pNext)
if (pNode->data == searchValue)
return (POSITION) pNode;
return NULL;
}
int CPtrList::GetCount() const
{
return m_nCount;
}
bool CPtrList::IsEmpty() const
{
return m_nCount == 0;
}
void*& CPtrList::GetHead()
{
return m_pNodeHead->data;
}
void* CPtrList::GetHead() const
{
return m_pNodeHead->data;
}
void*& CPtrList::GetTail()
{
return m_pNodeTail->data;
}
void* CPtrList::GetTail() const
{
return m_pNodeTail->data;
}
POSITION CPtrList::GetHeadPosition() const
{
return (POSITION) m_pNodeHead;
}
POSITION CPtrList::GetTailPosition() const
{
return (POSITION) m_pNodeTail;
}
void*& CPtrList::GetNext(POSITION& rPosition) // return *Position++
{
CNode* pNode = (CNode*) rPosition;
rPosition = (POSITION) pNode->pNext;
return pNode->data;
}
void* CPtrList::GetNext(POSITION& rPosition) const // return *Position++
{
CNode* pNode = (CNode*) rPosition;
rPosition = (POSITION) pNode->pNext;
return pNode->data;
}
void*& CPtrList::GetPrev(POSITION& rPosition) // return *Position--
{
CNode* pNode = (CNode*) rPosition;
rPosition = (POSITION) pNode->pPrev;
return pNode->data;
}
void* CPtrList::GetPrev(POSITION& rPosition) const // return *Position--
{
CNode* pNode = (CNode*) rPosition;
rPosition = (POSITION) pNode->pPrev;
return pNode->data;
}
void*& CPtrList::GetAt(POSITION position)
{
CNode* pNode = (CNode*) position;
return pNode->data;
}
void* CPtrList::GetAt(POSITION position) const
{
CNode* pNode = (CNode*) position;
return pNode->data;
}
void CPtrList::SetAt(POSITION pos, void* newElement)
{
CNode* pNode = (CNode*) pos;
pNode->data = newElement;
}
PtrList.h
// abstract iteration position
struct __POSITION { };
typedef __POSITION* POSITION;
struct CPlex // warning variable length structure
{
CPlex* pNext;
#if (_AFX_PACKING >= 8)
DWORD dwReserved[1]; // align on 8 byte boundary
#endif
// BYTE data[maxNum*elementSize];
void* data() { return this+1; }
static CPlex* Create(CPlex*& head, unsigned int nMax, unsigned int cbElement);
// like 'calloc' but no zero fill
// may throw memory exceptions
void FreeDataChain(); // free this one and links
};
class CPtrList
{
protected:
struct CNode
{
CNode* pNext;
CNode* pPrev;
void* data;
};
public:
// Construction
CPtrList(int nBlockSize = 10);
~CPtrList();
// Attributes (head and tail)
// count of elements
int GetCount() const;
bool IsEmpty() const;
// peek at head or tail
void*& GetHead();
void* GetHead() const;
void*& GetTail();
void* GetTail() const;
// Operations
// get head or tail (and remove it) - don't call on empty list!
void* RemoveHead();
void* RemoveTail();
// add before head or after tail
POSITION AddHead(void* newElement);
POSITION AddTail(void* newElement);
// add another list of elements before head or after tail
void AddHead(CPtrList* pNewList);
void AddTail(CPtrList* pNewList);
// remove all elements
void RemoveAll();
// iteration
POSITION GetHeadPosition() const;
POSITION GetTailPosition() const;
void*& GetNext(POSITION& rPosition); // return *Position++
void* GetNext(POSITION& rPosition) const; // return *Position++
void*& GetPrev(POSITION& rPosition); // return *Position--
void* GetPrev(POSITION& rPosition) const; // return *Position--
// getting/modifying an element at a given position
void*& GetAt(POSITION position);
void* GetAt(POSITION position) const;
void SetAt(POSITION pos, void* newElement);
void RemoveAt(POSITION position);
// inserting before or after a given position
POSITION InsertBefore(POSITION position, void* newElement);
POSITION InsertAfter(POSITION position, void* newElement);
// helper functions (note: O(n) speed)
POSITION Find(void* searchValue, POSITION startAfter = NULL) const;
// defaults to starting at the HEAD
// return NULL if not found
POSITION FindIndex(int nIndex) const;
// get the 'nIndex'th element (may return NULL)
// 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*);
public:
// local typedefs for class templates
typedef void* BASE_TYPE;
typedef void* BASE_ARG_TYPE;
};
제 생각에는..1. STL 을 사용한다.2. C++ Build
제 생각에는..
1. STL 을 사용한다.
2. C++ Builder에 있는 TList class를 적당히 가져온다
로 해결하시면 될 것 같습니다만.. :)
델파이의 TList는 C의 void* 형 컨테이너라고 생각하시면 됩니다.
델파이의 TList는 C의 void* 형 컨테이너라고 생각하시면 됩니다.
델파이나 C 모두 타입, 예외 안전은 제공하지 못하므로 어쩔 수 없이 이런 방식으로 사용해야 하고, 삽입되는 메모리의 해제는 (만약 할당한 메모리라면) 프로그래머의 책임입니다. (물론 TObjectList 같은 것은 자체적인 Free를 수행해주기도 합니다만 이건 예외적인 것이겠죠.)
C++ 에서는 여러가지가 있겠지만 평범한 :wink: 해결책으로는 STL의 컨테이너를 사용하고 boost::shared_ptr 을 사용해서 여러가지 잇점을 얻을 수 있을 것입니다.
STL 컨테이너 + shared_ptr 을 한번 써보시면 돌아가기 힘들지 않을까 합니다.
CPtrList
제생각에도 stl 쓰는것이 좋은 방법이라 생각되고요,
템플릿을 사용하지 않고, void* 형으로 사용하고 싶으시면,
MFC 에 CPtrList 라고 있습니다. 물론 윈도우용이고요
이걸 쪼금 고쳐서 리눅스용으로 만들어 봤습니다.
참고로, 검증이 안된 코드입니다.
PtrList.cpp
#include "afx.h" // <-- 여기엔 공통적으로 쓰이는 헤더화일을 적당히 넣어줍니다. #include "PtrList.h" CPlex* CPlex::Create(CPlex*& pHead, unsigned int nMax, unsigned int cbElement) { CPlex* p = (CPlex*) new unsigned char[sizeof(CPlex) + nMax * cbElement]; // may throw exception p->pNext = pHead; pHead = p; // change head (adds in reverse order for simplicity) return p; } void CPlex::FreeDataChain() // free this one and links { CPlex* p = this; while (p != NULL) { unsigned char* bytes = (unsigned char*) p; CPlex* pNext = p->pNext; delete[] bytes; p = pNext; } } CPtrList::CPtrList(int nBlockSize) { m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_nBlockSize = nBlockSize; } CPtrList::~CPtrList() { RemoveAll(); } void CPtrList::RemoveAll() { m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; } CPtrList::CNode* CPtrList::NewNode(CPtrList::CNode* pPrev, CPtrList::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; } } CPtrList::CNode* pNode = m_pNodeFree; m_pNodeFree = m_pNodeFree->pNext; pNode->pPrev = pPrev; pNode->pNext = pNext; m_nCount++; pNode->data = 0; // start with zero return pNode; } void CPtrList::FreeNode(CPtrList::CNode* pNode) { pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; m_nCount--; if (m_nCount == 0) RemoveAll(); } ///////////////////////////////////////////////////////////////////////////// POSITION CPtrList::AddHead(void* newElement) { CNode* pNewNode = NewNode(NULL, m_pNodeHead); pNewNode->data = newElement; if (m_pNodeHead != NULL) m_pNodeHead->pPrev = pNewNode; else m_pNodeTail = pNewNode; m_pNodeHead = pNewNode; return (POSITION) pNewNode; } POSITION CPtrList::AddTail(void* newElement) { CNode* pNewNode = NewNode(m_pNodeTail, NULL); pNewNode->data = newElement; if (m_pNodeTail != NULL) m_pNodeTail->pNext = pNewNode; else m_pNodeHead = pNewNode; m_pNodeTail = pNewNode; return (POSITION) pNewNode; } void CPtrList::AddHead(CPtrList* pNewList) { POSITION pos = pNewList->GetTailPosition(); while (pos != NULL) AddHead(pNewList->GetPrev(pos)); } void CPtrList::AddTail(CPtrList* pNewList) { POSITION pos = pNewList->GetHeadPosition(); while (pos != NULL) AddTail(pNewList->GetNext(pos)); } void* CPtrList::RemoveHead() { CNode* pOldNode = m_pNodeHead; void* returnValue = pOldNode->data; m_pNodeHead = pOldNode->pNext; if (m_pNodeHead != NULL) m_pNodeHead->pPrev = NULL; else m_pNodeTail = NULL; FreeNode(pOldNode); return returnValue; } void* CPtrList::RemoveTail() { CNode* pOldNode = m_pNodeTail; void* returnValue = pOldNode->data; m_pNodeTail = pOldNode->pPrev; if (m_pNodeTail != NULL) m_pNodeTail->pNext = NULL; else m_pNodeHead = NULL; FreeNode(pOldNode); return returnValue; } POSITION CPtrList::InsertBefore(POSITION position, void* newElement) { if (position == NULL) return AddHead(newElement); // insert before nothing -> head of the list CNode* pOldNode = (CNode*) position; CNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode); pNewNode->data = newElement; if (pOldNode->pPrev != NULL) { pOldNode->pPrev->pNext = pNewNode; } else { m_pNodeHead = pNewNode; } pOldNode->pPrev = pNewNode; return (POSITION) pNewNode; } POSITION CPtrList::InsertAfter(POSITION position, void* newElement) { if (position == NULL) return AddTail(newElement); // insert after nothing -> tail of the list CNode* pOldNode = (CNode*) position; CNode* pNewNode = NewNode(pOldNode, pOldNode->pNext); pNewNode->data = newElement; if (pOldNode->pNext != NULL) { pOldNode->pNext->pPrev = pNewNode; } else { m_pNodeTail = pNewNode; } pOldNode->pNext = pNewNode; return (POSITION) pNewNode; } void CPtrList::RemoveAt(POSITION position) { CNode* pOldNode = (CNode*) position; if (pOldNode == m_pNodeHead) { m_pNodeHead = pOldNode->pNext; } else { pOldNode->pPrev->pNext = pOldNode->pNext; } if (pOldNode == m_pNodeTail) { m_pNodeTail = pOldNode->pPrev; } else { pOldNode->pNext->pPrev = pOldNode->pPrev; } FreeNode(pOldNode); } POSITION CPtrList::FindIndex(int nIndex) const { if (nIndex >= m_nCount || nIndex < 0) return NULL; // went too far CNode* pNode = m_pNodeHead; while (nIndex--) { pNode = pNode->pNext; } return (POSITION) pNode; } POSITION CPtrList::Find(void* searchValue, POSITION startAfter) const { CNode* pNode = (CNode*) startAfter; if (pNode == NULL) { pNode = m_pNodeHead; // start at head } else { pNode = pNode->pNext; // start after the one specified } for (; pNode != NULL; pNode = pNode->pNext) if (pNode->data == searchValue) return (POSITION) pNode; return NULL; } int CPtrList::GetCount() const { return m_nCount; } bool CPtrList::IsEmpty() const { return m_nCount == 0; } void*& CPtrList::GetHead() { return m_pNodeHead->data; } void* CPtrList::GetHead() const { return m_pNodeHead->data; } void*& CPtrList::GetTail() { return m_pNodeTail->data; } void* CPtrList::GetTail() const { return m_pNodeTail->data; } POSITION CPtrList::GetHeadPosition() const { return (POSITION) m_pNodeHead; } POSITION CPtrList::GetTailPosition() const { return (POSITION) m_pNodeTail; } void*& CPtrList::GetNext(POSITION& rPosition) // return *Position++ { CNode* pNode = (CNode*) rPosition; rPosition = (POSITION) pNode->pNext; return pNode->data; } void* CPtrList::GetNext(POSITION& rPosition) const // return *Position++ { CNode* pNode = (CNode*) rPosition; rPosition = (POSITION) pNode->pNext; return pNode->data; } void*& CPtrList::GetPrev(POSITION& rPosition) // return *Position-- { CNode* pNode = (CNode*) rPosition; rPosition = (POSITION) pNode->pPrev; return pNode->data; } void* CPtrList::GetPrev(POSITION& rPosition) const // return *Position-- { CNode* pNode = (CNode*) rPosition; rPosition = (POSITION) pNode->pPrev; return pNode->data; } void*& CPtrList::GetAt(POSITION position) { CNode* pNode = (CNode*) position; return pNode->data; } void* CPtrList::GetAt(POSITION position) const { CNode* pNode = (CNode*) position; return pNode->data; } void CPtrList::SetAt(POSITION pos, void* newElement) { CNode* pNode = (CNode*) pos; pNode->data = newElement; }PtrList.h
// abstract iteration position struct __POSITION { }; typedef __POSITION* POSITION; struct CPlex // warning variable length structure { CPlex* pNext; #if (_AFX_PACKING >= 8) DWORD dwReserved[1]; // align on 8 byte boundary #endif // BYTE data[maxNum*elementSize]; void* data() { return this+1; } static CPlex* Create(CPlex*& head, unsigned int nMax, unsigned int cbElement); // like 'calloc' but no zero fill // may throw memory exceptions void FreeDataChain(); // free this one and links }; class CPtrList { protected: struct CNode { CNode* pNext; CNode* pPrev; void* data; }; public: // Construction CPtrList(int nBlockSize = 10); ~CPtrList(); // Attributes (head and tail) // count of elements int GetCount() const; bool IsEmpty() const; // peek at head or tail void*& GetHead(); void* GetHead() const; void*& GetTail(); void* GetTail() const; // Operations // get head or tail (and remove it) - don't call on empty list! void* RemoveHead(); void* RemoveTail(); // add before head or after tail POSITION AddHead(void* newElement); POSITION AddTail(void* newElement); // add another list of elements before head or after tail void AddHead(CPtrList* pNewList); void AddTail(CPtrList* pNewList); // remove all elements void RemoveAll(); // iteration POSITION GetHeadPosition() const; POSITION GetTailPosition() const; void*& GetNext(POSITION& rPosition); // return *Position++ void* GetNext(POSITION& rPosition) const; // return *Position++ void*& GetPrev(POSITION& rPosition); // return *Position-- void* GetPrev(POSITION& rPosition) const; // return *Position-- // getting/modifying an element at a given position void*& GetAt(POSITION position); void* GetAt(POSITION position) const; void SetAt(POSITION pos, void* newElement); void RemoveAt(POSITION position); // inserting before or after a given position POSITION InsertBefore(POSITION position, void* newElement); POSITION InsertAfter(POSITION position, void* newElement); // helper functions (note: O(n) speed) POSITION Find(void* searchValue, POSITION startAfter = NULL) const; // defaults to starting at the HEAD // return NULL if not found POSITION FindIndex(int nIndex) const; // get the 'nIndex'th element (may return NULL) // 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*); public: // local typedefs for class templates typedef void* BASE_TYPE; typedef void* BASE_ARG_TYPE; };frowt님의 답변에 감사드립니다. :D 거의 대부분의 님들이 방법론
frowt님의 답변에 감사드립니다. :D
거의 대부분의 님들이 방법론에 대하여 리플을 올려주시는데
frowt님께서는 소스코드를 올려 주셨으니...
근데 제 내공이 딸려서 제대로 이해하기는 힘드나 아뭏든 너무 감사드립니다.
사실 저는 델파이의 TList의 기능에 대한 이해가 안된 상태이거든요.
공부를 하면서 계속 참조해 보겠습니다.
그럼 좋은 하루 되세요..^^
kldp.net 에 많은 프로그래머들이 동참하기를 바라며...^^
댓글 달기