빌더에는 기본으로 DynamicArray가 내장되어 있습니다.
델파이의 다이나믹 어레이를 옮길때 사용하기 위해 제공하고 있는데,
사용법이 간단하고 쓰기 좋으나, TList 처럼 항목을 Add Delete 할수 없는
단점이 있습니다.
VC++의 ATL/WTL에 CSimpleArray라는 클래스가 있는데,
역시 다이나믹 어레이를 지원하는 템플릿 클래스로 Add Remove 와
DynamicArray 같이 바로 [ ] 로 배열로 참조할 수 있는,
데이타를 동적으로 관리할 수 있게 지원하는 클래스입니다.
구조체나 클래스를 동적배열로 관리하는 일은 플젝에서 매우
빈번하게 요구되는 일로, 쓸만한 클래스를 익혀 두는 것은 중요한 일입니다.
DynamicArray 가 다소 불편해서, WTL에서 CSimpleArray 클래스를 추출해
빌더에서 사용할 수 있게 수정했습니다.
일부 함수의 기능도 약간 수정했습니다.
물론, 빌더 뿐만 아니라 VC++에서도 이용가능합니다.
아래는 소스고 사용은 첨부파일을 이용하세요.
사용법은 소스 잠깐만 훑어 보시면 아실겁니다.
WTL를 가져다 쓸때 명칭이 중복될 수 있으므로, CSArray로 바꾸었습니다.
#ifndef CSimpleArrayH
#define CSimpleArrayH
#include <assert.h>
//---------------------------------------------------------------------------
inline void __declspec(noreturn) _AtlRaiseException( DWORD dwExceptionCode, DWORD dwExceptionFlags = EXCEPTION_NONCONTINUABLE )
{
RaiseException( dwExceptionCode, dwExceptionFlags, 0, NULL );
}
// Simple Struct Array class (WTL의 CSimpleArray를 수정 개선함)
template <class T> class CSArray
{
#define ATLASSERT assert
public:
CSArray() : m_aT(NULL), m_nSize(0), m_nAllocSize(0)
{
}
~CSArray()
{
RemoveAll();
}
CSArray(const CSArray<T>& src) : m_aT(NULL), m_nSize(0), m_nAllocSize(0)
{
m_aT = (T*)malloc(src.GetSize() * sizeof(T));
if (m_aT != NULL)
{
m_nAllocSize = src.GetSize();
for (int i=0; i<src.GetSize(); i++)
Add(src[i]);
}
}
CSArray<T>& operator=(const CSArray<T>& src)
{
if (GetSize() != src.GetSize())
{
RemoveAll();
m_aT = (T*)malloc(src.GetSize() * sizeof(T));
if (m_aT != NULL)
m_nAllocSize = src.GetSize();
}
else
{
for (int i = GetSize(); i > 0; i--)
RemoveAt(i - 1);
}
for (int i=0; i<src.GetSize(); i++)
Add(src[i]);
return *this;
}
// Operations
int GetSize() const
{
return m_nSize;
}
int Add(const T& t)
{
if(m_nSize == m_nAllocSize)
{
T* aT;
int nNewAllocSize = (m_nAllocSize == 0) ? 1 : (m_nSize * 2);
aT = (T*)realloc(m_aT, nNewAllocSize * sizeof(T));
if(aT == NULL)
return -1;
m_nAllocSize = nNewAllocSize;
m_aT = aT;
}
InternalSetAtIndex(m_nSize, t);
return m_nSize++;
}
bool Remove(const T& t)
{
int nIndex = Find(t);
if(nIndex == -1)
return false;
return RemoveAt(nIndex);
}
bool RemoveAt(int nIndex)
{
ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
if (nIndex < 0 || nIndex >= m_nSize)
return false;
m_aT[nIndex].~T();
if(nIndex != (m_nSize - 1))
memmove((void*)(m_aT + nIndex), (void*)(m_aT + nIndex + 1), (m_nSize - (nIndex + 1)) * sizeof(T));
m_nSize--;
return true;
}
void RemoveAll()
{
if(m_aT != NULL)
{
for(int i = 0; i < m_nSize; i++)
m_aT[i].~T();
free(m_aT);
m_aT = NULL;
}
m_nSize = 0;
m_nAllocSize = 0;
}
const T& operator[] (int nIndex) const
{
ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
if(nIndex < 0 || nIndex >= m_nSize)
{
_AtlRaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
}
return m_aT[nIndex];
}
T& operator[] (int nIndex)
{
ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
if(nIndex < 0 || nIndex >= m_nSize)
{
_AtlRaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
}
return m_aT[nIndex];
}
T* GetData() const
{
return m_aT;
}
int Find(const T& t) const
{
for(int i = 0; i < m_nSize; i++)
{
if(TEqual::IsEqual(m_aT[i], t))
return i;
}
return -1; // not found
}
BOOL SetAtIndex(int nIndex, const T& t)
{
if (nIndex < 0 || nIndex >= m_nSize)
return FALSE;
InternalSetAtIndex(nIndex, t);
return TRUE;
}
// Implementation
class Wrapper
{
public:
Wrapper(const T& _t) : t(_t)
{
}
template <class _Ty>
void * __cdecl operator new(size_t, _Ty* p)
{
return p;
}
template <class _Ty>
void __cdecl operator delete(void* /* pv */, _Ty* /* p */)
{
}
T t;
};
// Implementation
void InternalSetAtIndex(int nIndex, const T& t)
{
new(m_aT + nIndex) Wrapper(t);
}
//typedef T _ArrayElementType;
T* m_aT;
int m_nSize;
int m_nAllocSize;
};
//---------------------------------------------------------------------------
#endif
|