동일한 타입의 여러 데이터들을 저장할 수 있는 구조는
STL 컨테이너를 제외하고 대표적으로 배열과 리스트가 있다.
이번에는 리스트의 사용법과 대표적으로 사용되는 예시에대해서 알아보려고 합니다.
MFC에서 List형태의 자료구조는 다양하게 많은데
템플릿 리스트클래스는 CList가 있고
비 템플릿 리스트 클래스는 CObList, CStringList, CPtrList 정도가 있다.
CObList는 CObject 포인터를 데이터 타입으로 가지고,
CStringList는 CString을, CPtrList는 void 포인터를 데이터 타입으로 가진다.
CList를 사용하기 위해서는 "afxtempl.h" 헤더 파일을 #include 해줘야하고,
비템플릿 리스트 클래스들을 사용하기 위해서는 "afxcoll.h" 헤더를 #include 해줘야 한다.
개인적으로 가장 많이 사용하는 것은 CObList이다.
추가로 MFC의 CList 에 대한 자세한 정보는 MSDN을 참고하면 될 것 이다.
MFC의 리스트 클래스들은 모두 양방향 연결 리스트로 Head와 Tail을 모두 가지고 있다.
양방향 연결리스트의 장점은 어떤 방향이로든 이동할 수 있어 원하는 위치에 편하게 접근 할 수 있다.
이제 간단한 사용법에 대해서 알아 볼건데, 가장 많이 사용되는 함수들 위주로 설명하려고 한다.
MFC 리스트의 각 항목에 대한 접근은 POSITION 타입을 사용하여 이뤄진다.
소스 예제
//템플릿 클래스를 사용하기 위해 헤더 추가
// ....
// 나머지 헤더는 생략
#include <afxtempl.h>
using namespace std;
CList exList;
// 리스트의 뒤쪽에 데이터 삽입
for(int i = 0; i<10 ; i++)
exList.AddTail(i);
// 리스트의 앞쪽에 데이터 삽입
for(int i = 0 ; i<10 ; i++)
exList.AddHead(i);
// 전체 출력( 데이터 삽입, 삭제 전 )
// cout << "전 : " << endl;
POSITION pos = exList.GetHeadPosition();
while(pos)
{
int output = exList.GetNext(pos);
cout << output << " ";
}
cout << endl;
// POSITION을 이용한 데이터 삽입
pos = exList.GetHeadPosition();
while(pos)
{
const int five = 5;
int num = (int)exList.GetNext(pos);
if( num == five )
{
// 해당 position 기준으로 앞쪽에 100 삽입
exList.InsertBefore(pos, 100);
// 해당 position 기준으로 뒤쪽에 200 삽입
exList.InsertAfter(pos, 200);
// 해당 Position 위치 데이터 삭제
exList.RemoveAt(pos);
}
}
// 전체 출력( 데이터 삽입, 삭제 후 )
// cout << "후 : " << endl;
pos = exList.GetHeadPosition();
while(pos)
{
int output = exList.GetNext(pos);
cout << output << " ";
}
cout << endl;
POSITION을 사용하여 리스트를 하나씩 GetNext(pos) 다음으로 넘겨가며 원하는 위치에 접근 할 수 있다.
양방향 연결리스트인 만큼 반대로 Next가 아닌 이전으로도 이동할 수 있는데, 이는 GetPrev(pos) 를 사용하면 된다.
또한 리스트의 처음 시작 위치가 중요한데, 처음부터 시작하고 싶다면 GetHeadPostion()을,
리스트의 마지막 부터 시작하고 싶다면 GetTailPosition()을 사용하고.
특정 위치에 접근하고싶다면 GetAt() 을 사용 하면된다.
위의 소스에서 나와있듯이 데이터의 삽입 함수는
리스트의 마지막에 데이터를 삽입하는 AddTail() 과 리스트의 앞부분에 삽입하는 AddHead() 가 있고,
특정위치에 넣고싶다면 InsertBefore() 나 InsertAfter() 를 사용하면 된다.
데이터의 삭제 함수는
특정위치 삭제는 RemoveAt(), 리스트 전체 데이터를 삭제하고 싶다면 RemoveAll() 을 사용 하면된다.
MFC 프로젝트를 진행하면서 리스트는 정말 많이 사용 되는 구조고,
그중에서도 CObject로 특정 템플릿 데이터를 만들어 저장 후
POSITION을 이용하여 원하는 위치를 얻어와 적절한 타입으로 형변환 하여 사용을 많이하게 된다.
자세히 설명하면 더 길어 지겠지만,
간략히 이정도만 알아도 어느정도 리스트를 사용하는데에는 문제가 크게 없을 것이다.
참고사항
GetNext()와 GetPrev() 를 사용할 때 헷갈릴 여지가 있는 부분이 존재하는데,
함수만 읽어보면 바로 다음 포인터로 넘겨주어
그 다음이나 이전부분의 노드정보를 가져올 것으로 보이지만,
위 함수들은 먼저 지금 노드의 정보를 남기고 그 후에 다음 위치로 넘어간다.
따라서 GetAt()을 사용하거나 특정 위치를 알아야 할 때
GetNext() 진행 전에 미리 저장을 해두는 방법을 사용 해야한다.
GetNext(pos) 호출 전에 GetAt(pos)해보고, GetNext(pos) 호출 후에 GetAt(pos)를 사용하여
직접 디버깅 해보면 바로 이해가 갈 것이다.
'개발 > C++' 카테고리의 다른 글
[MFC] C++ 파일입출력 CFile/CArchive (직렬화. Serialize) (0) | 2021.08.26 |
---|---|
[C++] static 멤버 변수, static 멤버 함수에 대해 (+ mutable) (0) | 2021.08.24 |
[C++] 생성자, 소멸자, 복사생성자, 복사 대입 연산자, 복사생성 방지에 대한 얘기 (0) | 2021.02.17 |
안전한 정수 연산을 위해 SafeInt 를 써보자 (0) | 2020.07.13 |
VS 2017 환경에서 glog 설치 및 적용 방법 (0) | 2020.07.09 |
댓글