[GPG 3 글 1.8] GPG3권 1.8에서요..... 자동목록 설계 패턴 말이죠

GPG 시리즈 관련 질답, 논의 공간.

Moderator: 류광

bdoojin
Posts: 25
Joined: 2003-03-19 21:15

GPG3권 1.8에서요..... 자동목록 설계 패턴 말이죠

Post by bdoojin »

거기서 나온 소스 파일을 제 프로젝트에 적용시켜서

쓸려고 하는데요

컴파일 해보니깐

에러가 납니다

그래서 TAutolists.h를 보니 using namespace std;를 안쓰고 list앞에 std::가 안 붙었길래

다 붙여줬는데도

에러가 납니다

그래서 TestProject를 하나 만들고 실험해 봤는데 에러가 이렇게 나옵니다

Compiling...
autoliststest.cpp
c:\my documents\c++\autoliststest\tautolists.h(53) : error C2143: syntax error : missing ';' before '<'
c:\my documents\c++\autoliststest\tautolists.h(56) : see reference to class template instantiation 'TAutolists<T>' being compiled
c:\my documents\c++\autoliststest\tautolists.h(53) : error C2059: syntax error : '<'
c:\my documents\c++\autoliststest\tautolists.h(56) : see reference to class template instantiation 'TAutolists<T>' being compiled
c:\my documents\c++\autoliststest\tautolists.h(53) : error C2238: unexpected token(s) preceding ';'
c:\my documents\c++\autoliststest\tautolists.h(56) : see reference to class template instantiation 'TAutolists<T>' being compiled
c:\my documents\c++\autoliststest\tautolists.h(54) : error C2143: syntax error : missing ';' before '<'
c:\my documents\c++\autoliststest\tautolists.h(56) : see reference to class template instantiation 'TAutolists<T>' being compiled
c:\my documents\c++\autoliststest\tautolists.h(54) : error C2086: 'list' : redefinition
c:\my documents\c++\autoliststest\tautolists.h(56) : see reference to class template instantiation 'TAutolists<T>' being compiled
c:\my documents\c++\autoliststest\tautolists.h(54) : error C2059: syntax error : '<'
c:\my documents\c++\autoliststest\tautolists.h(56) : see reference to class template instantiation 'TAutolists<T>' being compiled
c:\my documents\c++\autoliststest\tautolists.h(54) : error C2039: 'iterator' : is not a member of '`global namespace''
c:\my documents\c++\autoliststest\tautolists.h(56) : see reference to class template instantiation 'TAutolists<T>' being compiled
c:\my documents\c++\autoliststest\tautolists.h(54) : error C2238: unexpected token(s) preceding ';'
c:\my documents\c++\autoliststest\tautolists.h(56) : see reference to class template instantiation 'TAutolists<T>' being compiled
c:\my documents\c++\autoliststest\tautolists.h(59) : error C2143: syntax error : missing ';' before '<'
c:\my documents\c++\autoliststest\tautolists.h(59) : error C2501: 'list' : missing storage-class or type specifiers
c:\my documents\c++\autoliststest\tautolists.h(59) : error C2059: syntax error : ';'
c:\my documents\c++\autoliststest\tautolists.h(59) : error C2143: syntax error : missing ';' before '<'
c:\my documents\c++\autoliststest\tautolists.h(59) : error C2065: 'T' : undeclared identifier
c:\my documents\c++\autoliststest\tautolists.h(59) : error C2039: 'ms_List' : is not a member of 'TAutolists'
c:\my documents\c++\autoliststest\tautolists.h(56) : see declaration of 'TAutolists'
c:\my documents\c++\autoliststest\tautolists.h(61) : error C2904: 'T' : template-name already defined as 'int T'
c:\my documents\c++\autoliststest\tautolists.h(61) : error C2039: 'iterator' : is not a member of '`global namespace''
c:\my documents\c++\autoliststest\tautolists.h(61) : error C2039: 'ms_ListIter' : is not a member of 'TAutolists'
c:\my documents\c++\autoliststest\tautolists.h(56) : see declaration of 'TAutolists'
C:\MY DOCUMENTS\C++\autoliststest\autoliststest.cpp(23) : error C2065: 'a' : undeclared identifier
C:\MY DOCUMENTS\C++\autoliststest\autoliststest.cpp(23) : error C2228: left of '.a' must have class/struct/union type
Error executing cl.exe.

autoliststest.exe - 19 error(s), 0 warning(s)

이거 어떻게 할수 없나요?
류광
Posts: 3805
Joined: 2001-07-25 09:00
Location: GPGstudy
Contact:

이거 우리가 한 번 해결해 봅시다...

Post by 류광 »

TAutoLists 클래스의 코드에 확실히 문제가 있습니다.(많습니다).

다만 위에 제시하신 엄청난 에러 메시지들은.. TAutoLists와 직접적인 관련은 없어 보입니다. 아마 소스 다른 어딘가에서 괄호나 중괄호, 세미콜론 등을 빼먹은 게 아닌가 싶구요.

진짜로 문제가 있는 부분은 우선 T*를 써야 할 부분에 그냥 T를 쓴 거.. 특히 list<T>요. list<T*>가 되어야 말이 됩니다.

그리고 STL list에 존재하지 않는 메서드들을 호출합니다. list::remove_at, list::find, list::get_next 등은 없는 것으로 알고 있습니다

GPG 시리즈의 품질을 볼 때 아예 안 되는 코드를 집어 넣지는 않았을 것이고... CD 제작 과정에서 뭔가 문제가 있는게 아닌가 싶네요(참고로 CD는 원서, 번역서 동일하고, 원서 홈페이지에 이 부분에 대한 정오표나 갱신 내용은 아직 없습니다).

이거 한 번 우리가 바로잡아보죠~ 다음은 제가 부분적으로 문제를 해결한(것처럼 보이는-.-) 코드입니다. 편의상 ASSERT는 생략했구요...(ASSERT가 어디에 정의되어 있는지 기억이 안났음-.-)

Code: Select all

#include <list>
using namespace std;

template <class T>
class TAutolists
{
public:
    TAutolists()
    {
        ms_List.push_front(static_cast<T*>(this));
    }

    virtual ~TAutolists()
    {
        ms_List.remove( static_cast<T*>(this) ); // remove로 고침
    }

public:
    static T* GetAutolistFirst()
    {
//        ASSERT(ms_ListIter==NULL);
        ms_ListIter = ms_List.begin ();
        if (ms_ListIter==NULL)
            return NULL;
        else
            return (*ms_ListIter);
    }

    static T* GetAutolistNext()
    {
        if (ms_ListIter==NULL)
            return NULL;
        else
            return ms_List.get_next(ms_ListIter);//이거 미완성
    }

    static unsigned int GetAutolistCount()
    {
        return ms_List.size ();
    }

private:

    // The actual list and list pointer
    static list<T*>            ms_List; // * 추가
    static list<T*>::iterator    ms_ListIter; // * 추가

};

// Declarations of static variables
template<class T> list<T*>    TAutolists<T>::ms_List; // * 추가

template<class T> list<T*>::iterator   // * 추가
        TAutolists<T>::ms_ListIter;
이 정도면 다음 코드는 돌아갑니다.(VC6)

Code: Select all

#include <iostream>
#include "TAutolists.h"

class CListMe:  public TAutolists<CListMe>
{
public:
	float a, b;

	CListMe() : a(1.0f), b(2.0f) { cout << "ctor" << endl; }
	~CListMe() { cout << "dtor" << endl; }
};

int main(void)
{
	CListMe cl1, cl2, cl3;

	CListMe* i = TAutolists<CListMe>::GetAutolistFirst();
	cout << i->a << endl;
	cout << TAutolists<CListMe>::GetAutolistCount() << endl;

	return 0;
}
GetAutolistNext()는 아직 안 됩니다. list::get_next()라는 알수없는 메서드를 호출하는데, 반복자 선언 입력하다 왠지 허무해져서 말았습니다. 쉽게 추가할 수 있을 것입니다....
류광
Posts: 3805
Joined: 2001-07-25 09:00
Location: GPGstudy
Contact:

Post by 류광 »

반복자 선언 입력할 필요 없었네요..

Code: Select all

...
    static T* GetAutolistFirst()
    {
        ms_ListIter = ms_List.begin ();
        ASSERT(ms_ListIter != ms_List.end() );
        if (ms_ListIter==ms_List.end() )
            return NULL;
        else
            return (*ms_ListIter++);
    }

    static T* GetAutolistNext()
    {
        if (ms_ListIter==ms_List.end())
            return NULL;
        else
            return *(ms_ListIter++);
    }
...
원래 코드의 의도에 따라 후위 증가를 사용했습니다(즉 현재의 원소를 반환하고 포인터를 하나 움직이는... DB의 fetch 비슷한 방식).

다음은 목록의 모든 원소에 접근하는 예..

Code: Select all

CListMe* p;

for(p = CListMe::GetAutolistFirst(); p != NULL; 
p = CListMe::GetAutolistNext() )
	cout << p->a << endl;


개념은 멋진데 구현은 별로 마음에 들지는 않네요. 무엇보다도.. 기왕 STL list를 사용했다면 외부 인터페이스 역시 반복자를 사용하게 하면 어떨까 싶구요. 내부 자료구조는 STL인데 외부는 포인터...
bdoojin
Posts: 25
Joined: 2003-03-19 21:15

클래스 A를 상속해 보니깐요

Post by bdoojin »

class A : TAutolists<A>
{
int a, b;
};

void main()
{
A a, b;
}

이런식으로 코드를 짜니

--------------------Configuration: autoliststest - Win32 Debug--------------------
Compiling...
autoliststest.cpp
c:\program files\microsoft visual studio\vc98\include\list(29) : error C2079: '_Value' uses undefined struct 'A'
c:\my documents\c++\autoliststest\tautolists.h(53) : see reference to class template instantiation 'std::list<struct A,class std::allocator<struct A> >' being compiled
C:\MY DOCUMENTS\C++\autoliststest\autoliststest.cpp(9) : see reference to class template instantiation 'TAutolists<struct A>' being compiled
c:\program files\microsoft visual studio\vc98\include\functional(185) : error C2079: 'value' uses undefined struct 'A'
c:\program files\microsoft visual studio\vc98\include\list(285) : see reference to class template instantiation 'std::binder2nd<struct std::not_equal_to<struct A> >' being compiled
c:\my documents\c++\autoliststest\tautolists.h(53) : see reference to class template instantiation 'std::list<struct A,class std::allocator<struct A> >' being compiled
C:\MY DOCUMENTS\C++\autoliststest\autoliststest.cpp(9) : see reference to class template instantiation 'TAutolists<struct A>' being compiled
Error executing cl.exe.

에러가 이렇게 뜹니다 A가 정의돼 있지 않다고 해서 그런거 같은데요 어떻게 고칠수 없나요?
bdoojin
Posts: 25
Joined: 2003-03-19 21:15

이제 됩니다

Post by bdoojin »

list<T>를 list<T*>로 바꾸니깐 됐습니다
bdoojin
Posts: 25
Joined: 2003-03-19 21:15

실제로 동작이 가능한 소스를 올려봅니다

Post by bdoojin »

// TAutolists.h: interface for the TAutolists class.
//
////////////////////////////////////////////////////

#ifndef _TAUTOLISTS_H_
#define _TAUTOLISTS_H_

#include <list>

using namespace std;

template <class T>
class TAutolists
{
public:
TAutolists()
{
ms_List.push_front(static_cast<T*>(this));
}

virtual ~TAutolists()
{
ms_List.remove(static_cast<T*>(this));
}

public:
static T* GetAutolistFirst()
{
//ASSERT(ms_ListIter==ms_List.end() );
ms_ListIter = ms_List.begin ();
if (ms_ListIter==ms_List.end())
return NULL;
else
return *(ms_ListIter++);
}

static T* GetAutolistNext()
{
if (ms_ListIter==ms_List.end())
return NULL;
else
return *(ms_ListIter++);
}

static unsigned int GetAutolistCount()
{
return ms_List.size ();
}

private:

// The actual list and list pointer
static list<T*> ms_List;
static list<T*>::iterator ms_ListIter;

};

// Declarations of static variables
template<class T> list<T*> TAutolists<T>::ms_List;

template<class T> list<T*>::iterator TAutolists<T>::ms_ListIter;

#endif

이겁니다

그리고 제가 실제로 써본 예제는

// autoliststest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include "TAutolists.h"

class CListMe : public TAutolists<CListMe>
{
public:
int a;

CListMe(int m) : a(m) { }

void print() { printf("%d\n", a); }
virtual ~CListMe() { }
};


int main(int argc, char* argv[])
{
CListMe a(10), b(20), c(25);
CListMe* plist = TAutolists<CListMe>::GetAutolistFirst();
while(plist) {
plist->print();
plist = TAutolists<CListMe>::GetAutolistNext();
}
return 0;
}

입니다 결과는
25
20
10
이것은 push_front를 하기 때문에 나중에 생성된 객체가 앞으로 들어가서 이렇게 되는겁니다
Gamza
Posts: 610
Joined: 2001-10-11 09:00
Contact:

Post by Gamza »

코딩중에 아래 부분에서 문제가 있었었는데요......

Code: Select all

static list<T*> ms_List;
자동목록이 지원되는 클래스들을 가지고 정적객체들을 선언할 경우,
ms_List의 생성자가 호출되기 전에, 자신을 삽입하려고 하는 객체가 생기더군요....
실제로는 map으로 했었을때 그랬었지만, list도 마찬가지 일것 같네요.

그래서 아래처럼 바꾸었는데....

Code: Select all

static list<T*>& GetList()
{
	static list<T*> s_List;
	return s_List;
}
함수가 헤더에 들어가는게 좀 찜찜 하네요.
혹시나 inline함수로 취급되면서,
내부의 static객체가 두개가 되어버리는 불상사가 일어나진 않을까 걱정이..
sparrowhawk

인라인 함수..

Post by sparrowhawk »

인라인 함수는 External-linkage이기 때문에, 정적 개체는 한번만 선언된다고

하는군요. (1996년 7월에 C++표준에서 결정했다더군요..)

참고자료는 Effective C++, More Effective C++입니다.

1996년 7월 이전에 만들어진 컴파일러 쓰시는 분은 주의하셔야 하겠습니다.
Gamza
Posts: 610
Joined: 2001-10-11 09:00
Contact:

Post by Gamza »

inline함수로 취급되면서,
내부의 static객체가 두개가 되어버리는 불상사가 일어나진 않을까 하는 걱정이....
현실이라 하네요.
viewtopic.php?t=2941

정적인 인스턴스를 지원하는 자동목록 패턴은 어떻게 구현해야 할지....
막바로 떠오르지는 않는군요...ㅡ.ㅡ

감자 성수올림...@~
Post Reply