#include <iostream>
using namespace std;

template<class A>
class SmartPointer {
public:
    SmartPointer() 
        : refCount(NULL), pointee(NULL) {
    }

    SmartPointer(A *pointee) 
        : refCount(new int(1)), pointee(pointee) {
    }

    SmartPointer(const SmartPointer &p)
        : refCount(p.getRefCount()), pointee(p.get()) {
        (*refCount)++;
        cout << "Copy constructor called" << endl;
    }

    ~SmartPointer() {
        reset();
    }

    void reset() {
        if (refCount) {
            (*refCount)--;
            if (*refCount == 0) {
                delete pointee;
                delete refCount;
            }
        }
        refCount = NULL;
        pointee = NULL;
    }

    void operator=(const SmartPointer &p) {
        reset();
        pointee = p.get();
        refCount = p.getRefCount();
    }

    const A &operator*() const {
        return *pointee;
    }

    const A *operator->() const {
        return pointee;
    }

    A &operator*() {
        return *pointee;
    }

    A *operator->() {
        return pointee;
    }

    A *get() const {
        return pointee;
    }

    int uses() const {
        return *refCount;
    }

    int *getRefCount() const {
        return refCount;
    }
private:
    A *pointee;
    int *refCount;
};

class A {
public:
    A() {
        cout << "A is created" << endl;
    }
    ~A() {
        cout << "A is deleted" << endl;
    }
};

void f(SmartPointer<A> p) {
    cout << "Working with p" << endl;
}

int main() {
    SmartPointer<A> p = new A();
    SmartPointer<A> q; // q ne pointe sur rien
    f(p);
    q = p;
    cout << "end main" << endl;
}
