#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;
}
*/
