7.27(금) C++ - iterator 의 구현

from Study/C++ 2007/07/30 14:48 view 40815

#include <iostream>

using namespace std;

 

template<typename T> class slist

{

        struct Node

        {

               T         data;

               Node* next;

               Node( T d, Node* n ) : data(d), next(n) {}

        };

        Node* head;

public:

        slist() : head(0)      {}

 

        void push_front( T a ) { head = new Node( a, head ); }

 

        // list의각요소를접근하기위해스마트포인터를넣는다.

        // 내포로만들거나외부에(그리고내부에typedef로선언) 만들수있다.

        class iterator

        {

               Node* current;

        public:

               typedef T value_type;

               iterator( Node* init = 0 ) : current( init ) {}

 

               iterator& operator++()

               {

                       current = current->next;

                       return *this;

               }

               T& operator* ()

               {

                       return current->data;

               }

               bool operator !=( const iterator& i )

               {

                       return (current != i.current);

               }

        };

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

        // 이제slist의처음과past the end iterator를리턴하는함수를제공한다.

        iterator begin() { return iterator(head); }

        iterator end() { return iterator( 0 ); }

};

/*

// 주어진구간의합을출력하는알고리즘을만들고싶다.

 

// 컴파일러에의한타입추론(type ??), 타입을알지못하므로컴파일러에게맡긴다??

// 단점: 리턴값을갖지못한다. 타입을모르므로?? void!!

template<typename T, typename T2> void sum_imp( T first, T last, T2 init )

{

        T2 s = init;

 

        while ( ++first != last )

        {

               s = s + *first;

        }

        cout << s << endl;

}

template<typename T> void sum( T first, T last )

{

        sum_imp( first, last, *first );

}

*/

 

// 버전2. 주어진구간의합을리턴하는함수를만들어보자.

// 모든반복자는자신과연관된typetypedef로가지고있다.( value_type으로꺼내면된다. )

 

// 간접층을만들어type문제를해결한다. (int, int), 반복자특성클래스.

template<typename T> struct xiterator_traits

{

        typedef typename T::value_type value_type;

};

 

// template 부분전문화( 포인터로되어있는것)

template<typename T> struct xiterator_traits<T*>

{

        typedef T value_type;

};

 

template<typename T>
typename xiterator_traits<T>::value_type sum( T first, T last )

{

        //typename T::value_type s = *first;
        //
어떠한타입이올지모르므로0을대입해서는안된다.

 

        typename xiterator_traits<T>::value_type s = *first;

 

        while ( ++first != last )

        {

               s = s + *first;

        }

        return s;

}

 

void main()

{

        int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        int n2 = sum( x, x+10 );

 

        slist<int> s;

 

        s.push_front( 10 );

        s.push_front( 20 );

        s.push_front( 30 );

        s.push_front( 40 );

 

        //slist안에있는모든요소의합을구하고싶다.

        int k = sum( s.begin(), s.end() );

 

        cout << k << endl;

}


////////////////////////////////////////////////////////////////////
// iterator_category 의 구현
template<typename T> struct xiterator_traits

{

        typedef typename T::value_type value_type;

        typedef typename T::iterator_category iterator_category;

};

 

// template 부분전문화( 포인터로되어있는것)

template<typename T> struct xiterator_traits<T*>

{

        typedef T value_type;

        typedef random_access_iterator_tag   iterator_category;

};

 

//임의접근일경우

template<typename T> void xadvance(T& p, int n ,random_access_iterator_tag)

{

        p += n;

}

 

template<typename T>

void xadvance( T& p, int n )

{

        xadvance( p, n, xiterator_traits<T>::iterator_category() );

}

 

void main()

{

        int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

 

        int *p = x;

 

        xadvance( p, 3 );   // p의반복자를3만큼전진해야한다. p+n 처리를하자.

 

        cout << *p << endl;    // 4이나와야한다.

}

Tag |

7.27(금) C++ - 일반적인 선형검색

from Study/C++ 2007/07/30 14:36 view 27398

#include <iostream>

using namespace std;

 

// 일반적프로그램의개념

// 선형검색: 주어진구간에서주어진조건을만족하는값을찾는다.

 

// 구간의조건: NULL 로끝나는문자열

// 구간의이동: ++

// 실패의경우: 0을리턴

// 단점: 반드시NULL을끝나는문자열이어야한다. - 너무특수한상황이다.

/*

char* xstrchr( char* s, int c )

{

        while( *s != 0 && *s != c )

               ++s;

 

        return *s == c ? s : (char*)0;

}

*/

 

// 보다일반화한버전.

// 주어진구간의조건: [begin , end) - 반개행구간. 한쪽만열려있다는의미>> [ ~ )

// 이때endpast the end 라고한다.

// 구간의이동: ++

// 실패의처리: past the end

// 장점: 부분문자열검색이가능하다-> 보다일반화되었다.

// 단점: 문자열(char)만검색가능하다. -> template으로일반화하자.

/*

char* xstrchr( char* begin, char* end, int c )

{

        while( begin != end && *begin != c )

               ++begin;

 

        return begin;

}

void main()

{

        char s[10] = "ABCDEFG";

        //char* c = xstrchr( s, 'C' );

        char *c = xstrchr( s, s+4, 'C' );

 

        if ( c == s + 4 )

        {

               cout << "실패" << endl;

        }

        else

               cout << *c << endl;

}

*/

 

// 버전3. template의도입

// 모든type의배열로부터선형검색을수행한다.!!

/*

template<typename T1, typename T2> T1 find( T1 first, T1 last, T2 value )

{

        while( first != last && *first != value )

               ++first;

 

        return first;

}

 

void main()

{

        int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

 

        int* p = find( x, x+10, 3 );

 

        if( p == x+10 )

        {

               cout << "값을찾을수없습니다." << endl;

        }

        else

               cout << *p << endl;

}

*/

 

// 이제Single Linked List를고려해보자.

template<typename T> class slist

{

        struct Node

        {

               T         data;

               Node* next;

               Node( T d, Node* n ) : data(d), next(n) {}

        };

        Node* head;

public:

        slist() : head(0)      {}

 

        void push_front( T a ) { head = new Node( a, head ); }

 

        // list의각요소를접근하기위해스마트포인터를넣는다.

        // 내포로만들거나외부에(그리고내부에typedef로선언) 만들수있다.

        class iterator

        {

               Node* current;

        public:

               iterator( Node* init = 0 ) : current( init ) {}

 

               iterator& operator++()

               {

                       current = current->next;

                       return *this;

               }

               T& operator* ()

               {

                       return current->data;

               }

               bool operator !=( const iterator& i )

               {

                       return (current != i.current);

               }

        };

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

        // 이제slist의처음과past the end iterator를리턴하는함수를제공한다.

        iterator begin() { return iterator(head); }

        iterator end() { return iterator( 0 ); }

};

 

// 모든type의모든자료구조로부터선형검색을수행한다.!!

template<typename T1, typename T2> T1 find( T1 first, T1 last, T2 value )

{

        while( first != last && *first != value )

               ++first;

 

        return first;

}

 

// 모든type의모든자료구조로부터선형검색을수행한다.!!

// 상수가아닌조건을만족하는것을찾는다.주어진조건을찾는다!!!

template<typename T1, typename T2> T1 find_if( T1 first, T1 last, T2 pred )

{

        while( first != last )

        {

               if ( pred(*first) )

                       break;

               ++first;

        }

 

        return first;

}

bool foo( int a )

{

        return a % 3 == 0;

}

 

void main()

{

        int x[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

 

        int* p2 = find_if( x, x+10, foo );

 

        cout << *p2 << endl;

//////////////////////////////////////////////////

        slist<int> s;

 

        s.push_front(10);

        s.push_front(20);

        s.push_front(30);

        s.push_front(40);

 

        slist<int>::iterator p = find( s.begin(), s.end(), 20 );

 

        cout << *p << endl;

        ++p;

        cout << *p << endl;

/////////////////////////////////////////////////

        p = find_if( s.begin(), s.end(), foo );

        cout << *p << endl;

}

 

Tag |

7.27(금) C++ - 스마트포인터

from Study/C++ 2007/07/30 14:34 view 25213

#include <iostream>

using namespace std;

 

// 1) 개념: -> 연산자를재정의해서다른객체의포인터역할을하는객체.

// 2) 원리: -> 연산자재정의

// 3) 장점: 자원관리를자동으로할수있다.

// 4) explicit 생성자SPTR<int> p2( new int ); 로생성해야한다.

// 5) Owner Ship 관리- 중요!

 

class Test

{

public:

        int x;

        void foo() { cout << "Test::foo" << endl; }

};

 

template<typename T> class SPTR

{

        T* _obj;

        int* pCount;   // 참조카운팅을하기위해

 

public:

        explicit SPTR( T* p ) : _obj(p)

        {

               pCount = new int(1);          // 힙에카운팅을만든다.!!

        }

 

        ~SPTR()

        {

               if( --(*pCount) == 0 )

               {

                       delete _obj;

                       delete pCount;

               }

        }              // 자동삭제가능.

 

        T* operator->() { return _obj; }

        T& operator *() { return *_obj; }

 

        // 참조개수기법으로구현한복사생성자

        SPTR( const SPTR& s )

        {

               _obj = s._obj;

               pCount = s.pCount;

               ++(*pCount);

        }

 

        /*

        // 소유권이전

        SPTR( SPTR<T>& s )

        {

               _obj = s._obj;

               s.obj = 0;

        }

        */

};

 

void main()

{

        SPTR<Test> p1( new Test );

       

        SPTR<Test> p2 = p1;

}

 

/* 1) ~ 4)

void main()

{

        //SPTR<int> p2 = new int;             // explicit 생성자라서error

       

        SPTR<int> p2( new int );

        *p2 = 20;

        cout << *p2 << endl;

 

        //Test* p = new Test;

        //SPTR<Test> p = new Test;    // SPTR P( new Test );

        SPTR<Test> p( new Test );     // SPTR p( new Test );

 

        (*p).x = 10;

 

        cout << (*p).x << endl;

 

        p->foo();                     // (p.operator->())foo() 이지만

                                             // 컴파일러가(p.operator->())->foo()로해석해준다.

}

*/

 

 

/*      스마트포인터에장점!!

void ReleaseFucntion( FILE * f)

{

        fclose(f);

}

 

void foo()

{

        //int* p = new int;

        SPTR<int> p( new int );       // Resource Acqusion Is Initialize (RAII)

        {

               //fclose 를대신할ReleaseFucntion !!

               //생성자에서함수포인터를받아서delete할때ReleaseFucntion 호출

               //SPTR<FILE> p2( fopen( "a.txt", "wt" ), ReleaseFucntion );

               SPTR<FILE> p2( fopen( "a.txt", "wt" ), fclose );

        }

 

        if ( n == 0 )

        {

               //delete p;

               return;

        }

 

        //delete p;

}

*/


Tag |

// explicit 없이 암시적인 변환을 막는다.(간접층 사용! proxy)

class Stack

{

        struct ploxy{

               int *buf;

               int top;

 

               proxy(int _sz):top(_sz),buf(new int[_sz])

               {

                       cout << "ploxy()" << endl;

               }

               ~proxy()

               {

                       cout << "~ploxy()" << endl;

                       delete buf;

               }

        };

        int * buf;

        int top;

 

public:

 

        Stack(proxy a):buf(a.buf),top(a.top)

        {

               cout << "Stack()" << endl;

        }

};

 

void foo(Stack s)

{

        cout << "foo()" << endl;

}

 

void main()

{

        Stack s(10);

        foo(s);

        //foo(100); //error

}

 //////////////////////////////////////////////////////////////////////////
class
Stack

{

        int* buf;

        int top;

public:

        // 인자1개인생성자가암시적인변환의의미로사용되는것을막는다.

        // , 명시적변환은허용된다.

        explicit Stack( int sz = 10 ) {}

};

 

void foo( Stack s )

{

}

 

void main()

{

        Stack s;

        foo( s );

 

        foo( 100 );
         // 100 -> stack
이라면가능int->stack(변환생성자, 인자개인생성자!!

}

//////////////////////////////////////////////////////////////////////////
//
변환이야기.


void main()

{

        int n;

        cin >> n;      // 만약문자를입력하면실패한다.

 

        if( cin )
// cin.operaotr bool()
로변환되면가능하다. cin은객체이지만if문안에들어갈수이유는???

// 실제로는cin.operator void*()로되어있다.

        {

               cout << "성공" << endl;

        }

}
//////////////////////////////////////////////////////////////////////////

class Point

{

        int x;

        int y;

public:

        // 인자가1개인생성자=> 변환생성자라고불린다.

        Point( int a ) : x(a), y(0) {}

 

        Point( int a = 0, int b = 0 ) : x(a), y(b) {}

 

// 변환연산자: Point int로변하게된다. 리턴값을표기하지않는다. 함수이름에리턴값있다.!!

        operator int()

        {

               return x;

        }

};

 

void main()

{

        Point p( 1, 2 );

        int n = 10;

 

        p = n;                 // int -> Point로변환되게한다. 변환생성자

 

        double d = 3.2;

        int n = d;

 

        Point p1( 1, 2 );

 

        int n2 = p1;   // ?Point -> int로변환p1.operator int() 가있으면된다.

}

 

Tag |

7.26(목) C++ 기초문법 - ostream

from Study/C++ 2007/07/30 14:20 view 62820

#include <iostream>

using namespace std;

 

namespace AAA

{

        class Point

        {

               friend ostream& operator<<(ostream& os, const Point& aaa)

               {

                       return os;

               }

        };

 

}

 

void main()

{

        AAA::Point p;

 

//      AAA::operator<<(cout, p);
// error : cout.operator<<( AAA::Point),
처리하자!!

 

        cout << p;     // 인자기반탐색이가지는장점.!!

}

 

 

 

// cout, endl 의원리

#include <stdio.h>

 

class ostream

{

public:

        ostream& operator<<(char* s)

        {

               printf(s);

               return *this;

        }

        ostream& operator<<( ostream&(*f)(ostream&))

        {

               return f(*this);

        }

};

 

ostream cout;

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

ostream& endl(ostream& os)

{

        os << "\n";

        return os;

}

 

ostream& two_endl(ostream& os)        // ostream에확장가능하다!!!!

{

        os << "\n\n";

        return os;

}

 

void main()

{

        cout << "hello";       // cout.operator<<("hello")

        cout << two_endl;

        cout << endl;          // cout.operator<<(함수포인터)

        cout << "hello";       // cout.operator<<("hello")

 

        endl( cout );

}

 

Tag |

// 1. const_cast

int main()

{

        const int c = 10;

        int* p2 = const_cast<int*>(&c);
// error :
원본이 const이면 벗겨내지 못한다.

 

        int n = 10;

        const int* p = &n;  // ok

 

        int* p3 = const_cast<int*>(p);
//ok :
접근 하는 놈이 const이면 벗겨 낼 수 있다.     

}

// 2. 상수함수: 멤버의값을바꿀수없다.

// const 객체는const 함수만호출가능

// 반드시멤버의값을바꾸지않는다면const 함수로만들어라.

class Point

{

        int x;

        int y;

//      string cache;

//      bool   cache_valid;

 

        // 상수함수내에서도값을변경할수있다.

        mutable string cache;

        mutable bool   cache_valid;

 

public:

        Point( int a = 0, int b = 0 ) : x(a), y(b), cache_valid(false) {}

 

        string to_string() const

        {

               if( cache_valid == false )

               {

                       char buf[256];

                       sprintf( buf, "%d", "%d", x, y );

 

                       cache = buf;

                       cache_valid = true;

               }

               return cache;

        }

};

 

void main()

{

        const Point p(1, 2);

 

        cout << p.to_string() << endl;

}


 // 3. mutable을 사용하는 대신에 논리적 상수성을 사용한다.incrementation??
 // logical constness( 논리적 상수성. ) - lazy evaluation의 기법이기도 하다.

struct cache

{

        bool valid;

        string rep;

 

        cache(){ valid = false; }

};

 

class Point

{

        int x, y;

        cache* c;

 

public:

        Point( int a = 0, int b = 0 ) : x(a), y(b)

        {

               c = new cache();

        }

        ~Point()

        {

               if (c != NULL)

                       delete c;

        }

 

        string to_string() const

        {

               if ( c->valid == false )

               {

                       char buf[256];

                       sprintf( buf, "%d", "%d", x, y );

 

                       c->rep = buf;

                       c->valid = true;

               }

 

               return c->rep;

        }

 

};

 

void main()

{

        const Point p(1, 2);

 

        p.to_string();

}


Tag |

http://minjang.egloos.com/1458391 // 이문제에 대한 좋은 사례.

//
멤버함수 포인터의 크기, 가상함수 일때 크기, 상속이 있을때, 상속이 있을때 가상함수.

// 최대16byte 까지나온다. ??? boost??

 

// 다중상속과가상상속일때크기가달라집니다.

class  A

{

public:

        virtual void foo(int ) {}

};

class B : virtual public A

{

public:

        virtual void foo(int ){}

};

 

typedef void( B::*FUNC )();

 

void main()

{

        // 같은 표현
       
cout << sizeof( &B::foo ) << endl;

        cout << sizeof( FUNC ) << endl;
}

Tag |

// 일반 멤버 함수포인터를 만들 때에는 thiscall을 생각해서 'Point::'를 추가해주자!!
// void(Point::*f3)() = &Point::hoo;

class
Point

{

public:

        //this가인자로전달되지않는멤버함수.

        static void foo( int a )
        { cout << "foo()" << endl; }

        void hoo()

        { cout << "hoo()" << endl; }

};

 

void goo( int a )

{

        cout << "goo()" << endl;
}

 

int main()

{

        void(*f1)(int) = &goo;

        void(*f2)(int) = &Point::foo;

 

        // 일반멤버함수의 주소

        void(Point::*f3)() = &Point::hoo;

 

        //f3(); // 될까? 안된다-> 객체가없다. this를전달해주지못한다.

 

        Point p;

        (p.*f3)();   // ().을 우선으로 연산하고 *를 하여서 함수포인터를 호출!

}

Tag |

// 멤버함수의호출원리

class A

{

        int x;

public:

        void foo( int a )      // void foo( Point* const this, int a)

        {

               x = a;                 // this->x = a;

        }

};

 

void main()

{

        A a1, a2;

        a1.foo(10);  // foo( &a1, 10 );

        // push &a1 이 아니라 mov ecx, &a1
        // a1 , 즉 this
에 대한 인자는 레지스터로 보낸다.( thiscall )

        // push 10

        // call foo

}

Tag |

// 싱글톤 : 객체가 하나만 생성되게 한다.


// Mayer
singleton( stack 이용 )

class MouseCursor

{

private:

        MouseCursor() {}

public:

        static MouseCursor& GetInstance()

        {

               static MouseCursor m;

               return m;

        }

};

 

void main()

{

        MouseCursor& m1 = MouseCursor::GetInstance();

        MouseCursor& m2 = MouseCursor::GetInstance();

}

//heap 공간에singleton 구현하기

#include <iostream>

using namespace std;

 

class Singleton

{

private:

        static Singleton* m_cursor;

        Singleton() {}

        Singleton(const Singleton&);

        ~Singleton()

        {

               if ( m_cursor != NULL )

               {

                       delete m_cursor;

               }

        } 

 

public:

        static Singleton* GetInstance()

        {

               if (m_cursor == NULL)

                       m_cursor = new Singleton();

               return m_cursor;

        }

};

 

Singleton* Singleton::m_cursor = NULL;

 

void main()

{

        Singleton* single1 = Singleton::GetInstance();

        Singleton* single2 = Singleton::GetInstance();

}


// Double Checked Locking Singleton( 윈도우- 멀티스레드환경대비)

// 객체를 생성할 때 CRITICAL_SECTION 으로 감싸준다.
#include
<iostream>

#include <windows.h>

using namespace std;

 

class CriticalSection

{

private:

        CRITICAL_SECTION cs;

public:

        CriticalSection() { InitializeCriticalSection(&cs); }

        ~CriticalSection() { DeleteCriticalSection(&cs); }

 

        void Enter()

        {

               EnterCriticalSection(&cs);

        }

        void Leave()

        {

               LeaveCriticalSection(&cs);

        }

};

 

CriticalSection g_cs;

 

class Singleton

{

private:

        static Singleton* m_cursor;

       

        Singleton() {}

        Singleton(const Singleton&);

        ~Singleton()

        {

               if ( m_cursor != NULL )

               {

                       delete m_cursor;

               }

        } 

 

public:

        static Singleton* GetInstance()

        {

               if (m_cursor == NULL)

               {

                       m_cursor = new Singleton();

               }

               return m_cursor;

        }

};

 

Singleton* Singleton::m_cursor = NULL;

 

DWORD WINAPI SingletonProc(void* pv)

{

        Singleton* pSingle = NULL;

 

        while (1)

        {

               if (pSingle == NULL)

               {

                       g_cs.Enter();

                       pSingle = Singleton::GetInstance();

                       cout << "Singleton create : " << pSingle << endl;

                       g_cs.Leave();

               }

               Sleep(0);

        }

        return 0;

}

 

void main()

{

        HANDLE hThread[2];

 

        hThread[0] = CreateThread( NULL, 0, SingletonProc, NULL, 0, NULL );

        hThread[1] = CreateThread( NULL, 0, SingletonProc, NULL, 0, NULL );

 

        WaitForMultipleObjects(2, hThread, TRUE, INFINITE);

        CloseHandle(hThread[0]);

        CloseHandle(hThread[1]);

}

Tag |