C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

컴포넌트/라이브러리
Delphi/C++Builder Programming Components&Libraries
[474] Template TList, 형을 지정할 수 있는 유사 TList. (버그 수정됨. 3)
김태선 [jsdkts] 13904 읽음    2006-05-20 10:19
원래 TList는 델파이에서 디자인 되어진 델파이 특성에 맞는 클래스라서 C++의 다양한 기능을 구사하는데
상당히 부족합니다. 사용하다 보면 C++ 스타일로 사용하는게 아니라 델파이 스타일로
사용해야 하기 때문에 보다 나은 클래스를 원하게 됩니다.
이곳 볼포 자료실에 TTypedList 가 소개되어 있기는 하지만 TList를 상속받아
다만 형만 캐스팅 없이 사용할 수 있게 하였을 뿐이므로, 여전히 부족함을 느끼게 되었습니다.
그래서 C++로만 짜여진 대체할만한 TList를 찾았으나, 결국 찾지 못해서
(찾고 보면 델파이의 TList를 C++로 옮겨 놓은 것이 아닌 거의 Linked List 를 구현한 것이더군요.)
그냥 만들어 쓰자 싶어 만들게 되었으며, 실무에 매우 유용하리라 판단되어 공개합니다.

TList의 기능중 핵심적인 내용은 대부분 구현했으며,
(TList의 Sort 기능은 qsort(...); 로 대체해서 사용하면 됩니다)
일단의 테스트에서는 매우 안정적으로 동작합니다.
순수 C++ 스타일 템플릿클래스이므로 간단한 데이타를 다루는데는 유용할 것입니다.
또한, 이 클래스를 상속받아 커스트마이징해서 자신만의 데이타를 다루는데 이용해도 좋을 것입니다.

혹시 모를 버그가 발견되거나 기능이 개선되면 다시 올려 놓겠습니다.
현재 2차 수정 되었습니다.
현재 3차 수정되었습니다. Exchange 함수에서 메모리 누수 가능성 수정.
//---------------------------------------------------------------------------
/*
    Template TList
    형을 지정할 수 있는 유사 TList.
    즉 4바이트의 포인트나 값만을 저장하는 TList 가 아니라,
    TList 와 사용법은 비슷하면서 아무형이나 그 형자체를 저장할수 있는 것이 틀리다.
    WTL 7.5의 CSimpleArray를 기반으로 TList 스타일로 수정해서 만듦.

    특징
        템플릿으로 구현되었으므로 형 자체를 저장할 수 있다.
        VCL 스타일 클래스가 아니므로 스택에 생성할수 있다.
        아이템 삭제나 객체소멸시 각 개별 객체에 대해 자동으로 소멸자를 호출 한다.
        이어진 메모리경계를 가진 동적 배열이다.
        동적 배열이므로 STL로 변환해 다루기 쉽다.

    ver1.0
    Written by 김태성 jsdkts@korea.com
*/
#ifndef TTListH
#define TTListH

//---------------------------------------------------------------------------

template <class T>
class TTList
{
public:
    __property int  Count = { read=m_nSize };    // C++Builder Only.
public:
    TTList() : m_aT(NULL), m_nSize(0), m_nAllocSize(0)
    {
    }
    virtual ~TTList()
    {
        Clear();
    }
    TTList(const TTList<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]);
        }
    }
    TTList<T>& operator=(const TTList<T>& src)
    {
        if (GetSize() != src.GetSize())
        {
            Clear();
            m_aT = (T*)malloc(src.GetSize() * sizeof(T));
            if (m_aT != NULL)
                m_nAllocSize = src.GetSize();
        }
        else
        {
            for (int i = GetSize(); i > 0; i--)
                Delete(i - 1);
        }
        for (int i=0; i < src.GetSize(); i++)
            Add(src[i]);
        return *this;
    }

    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 Delete(int nIndex)
    {
        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;
    }
    // 일치하는 값을 가진 첫번째 항목을 지운다.
    bool DeleteValue(const T& t)
    {
        int nIndex = IndexOf(t);
        if(nIndex == -1)
            return false;
        return Delete(nIndex);
    }
    // 주어진 인덱스 번호에 항목을 끼워 넣는다.
    bool Insert(int nIndex, const T& t)
    {
        if (nIndex < 0 || nIndex >= m_nSize)
            return false;
        if (Add(t) == -1)   // 공간확보용.
            return false;
        System::Move(m_aT + nIndex, m_aT + nIndex + 1, (m_nSize - nIndex - 1) * sizeof(T));
        m_aT[nIndex] = t;
        return true;
    }
    // 두항목의 저장위치를 바꾼다.
    void    Exchange(int index1, int index2)
    {
        if (index1 < 0 || index1 >= m_nSize)
            return;
        if (index2 < 0 || index2 >= m_nSize)
            return;
        byte  *p = new byte[sizeof(T)];    // 생성자를 가정할수 없으므로 공간만 확보한다.
        memmove((void*)p, (void*)(m_aT + index1), sizeof(T));
        memmove((void*)(m_aT + index1), (void*)(m_aT + index2), sizeof(T));
        memmove((void*)(m_aT + index2), (void*)p, sizeof(T));
        delete[] p;
    }
    void Clear()
    {
        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;
    }
    // TList의 Get, Put은 C++에서는 아래 []로 더 편리하게 사용가능하므로 생략함.
    const T& operator[] (int nIndex) const
    {
        if(nIndex < 0 || nIndex >= m_nSize)
        {
            _RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
        }
        return m_aT[nIndex];
    }
    T& operator[] (int nIndex)
    {
        if(nIndex < 0 || nIndex >= m_nSize)
        {
            _RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
        }
        return m_aT[nIndex];
    }
    T* begin() const    // like STL
    {
        return m_aT;
    }
    T* end() const        // like STL
    {
        return m_aT + m_nSize;
    }
    int IndexOf(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;
    }
private:
    // Implementation
    class Wrapper
    {
    public:
        Wrapper(const T& _t) : t(_t)
        {
        }
        template <class _Ty>
        void * __cdecl operator new(size_t, _Ty* p)
        {
            return p;
        }
        T t;
    };
    // Implementation
    void InternalSetAtIndex(int nIndex, const T& t)
    {
        new(m_aT + nIndex) Wrapper(t);
    }

private:
    T*     m_aT;
    int m_nSize;
    int m_nAllocSize;

    // Operations, VC++과의 호환성을 위해 그대로 둔다.
    int GetSize() const
    {
        return m_nSize;
    }
    inline void __declspec(noreturn) _RaiseException( DWORD dwExceptionCode, DWORD dwExceptionFlags = EXCEPTION_NONCONTINUABLE )
    {
        RaiseException( dwExceptionCode, dwExceptionFlags, 0, NULL );
    }
};

//---------------------------------------------------------------------------


#endif



테스트 코드
//---------------------------------------------------------------------------
class TB
{
public:
    int  k;
    TB(int seed) // = 100)
        : k(seed)
    {
        k++;
    }
};

class TA : public TB    // 상속
{
    int        temp;
public:
    TB    b;                // 합성
    TA(int  k)
        : b(k),
        TB(k)
    {
        b.k++;
    }
};
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
    TA b(0);                // b.k == 1
   
    TTList<TA> a;
    a.Add(b);    b.k++;        // 1
    a.Add(b);    b.k++;        // 1,2
    a.Add(b);    b.k++;        // 1,2,3
    a.Add(b);    b.k++;        // 1,2,3,4
    a.Add(b);    b.k++;        // 1,2,3,4,5
    a.Insert(2, b);            // 1,2,6,3,4,5
    a.Exchange(1,2);        // 1,6,2,3,4,5
    a.Delete(3);            // 1,6,2,4,5
    for(int c = 0; c < a.Count; c++)
        Memo1->Lines->Add(a[c].k);

    // 포인트를 저장하면 TList에 포인트를 저장해서 사용하는 것과 비슷하다.
    // 물론 포인트만을 저장해서 사용할 경우는 aa.Delete(0); 같은 삭제함수를 부르더라도
    // 포인트 값은 삭제되어도 당연히 소멸자는 호출되지 않는다.
    TTList<TA *> aa;
    b.k++;
    aa.Add(&b);                // 7
    Caption = aa[0]->k;
}
//---------------------------------------------------------------------------


화면에 찍히는 결과

Memo1
1
6
2
4
5

캡션에는
7 이 찍힙니다.

그럼.
윤승환 [epilogs]   2006-10-17 15:22 X
성능은 어떤가요?
김태선 [cppbuilder]   2006-12-07 15:45 X
웬만한 목적에는 아무 무리 없이 사용할 수 있습니다.

+ -

관련 글 리스트
474 Template TList, 형을 지정할 수 있는 유사 TList. (버그 수정됨. 3) 김태선 13904 2006/05/20
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.