#include <iostream>
#include <memory>
#include <map>
using namespace std;
#define Msg1(msg) {cout << (msg) << endl;}
#define Msg2(msg1,msg2) {cout << (msg1) << (msg2) << endl;}
#define Msg2s(msg1,msg2,sp) {cout << (msg1) << (sp) << (msg2) << endl;}
#define DebugMode
#ifdef DebugMode
# define DebugMsg1(msg) Msg1(msg)
#else
# define DebugMsg1(msg)
#endif
class NullPtr_t
{
public:
NullPtr_t() : zero(NULL) {}
template< class T >
operator T* () const { return NULL; }
template< class T, class C >
operator T C::* () const { return NULL; }
private:
void operator &() const;
void *zero;
};
inline NullPtr_t getNullPtr() { return NullPtr_t(); }
#define nullptr getNullPtr()
template< class T >
class BasePtr
{
typedef BasePtr< T > ThisPtr;
virtual T* get() = 0;
virtual T& ref() = 0;
friend bool operator == (ThisPtr& a, ThisPtr& b) {
return a.get() == b.get();
}
friend bool operator != (ThisPtr& a, ThisPtr& b) {
return a.get() != b.get();
}
};
template< class T, class A = allocator< T > >
class FooPtr : public BasePtr< T >
{
typedef T FOO, *LPFOO;
typedef A ALLO;
typedef map< LPFOO, int > REFMAP;
typedef FooPtr< FOO , ALLO > ThisPtr;
private:
LPFOO _ptr;
REFMAP& refmap() {
static REFMAP refm;
return refm;
}
public:
FooPtr() : _ptr(nullptr) {
}
FooPtr(const LPFOO foo) : _ptr(nullptr) {
DebugMsg1( "FooPtr(LPFOO)" );
reset(foo);
}
FooPtr(const ThisPtr& other) : _ptr(nullptr) {
DebugMsg1( "FooPtr(ThisPtr)" );
copy(other);
}
~FooPtr() {
clear();
}
FOO& operator *() const { return *_ptr; }
operator LPFOO const () { return _ptr; }
LPFOO operator -> () const { return _ptr; }
LPFOO get() { return _ptr; }
FOO& ref() { return *_ptr; }
ThisPtr& operator = (const ThisPtr& other) {
DebugMsg1( "ope = ThisPtr" );
copy(other);
return *this;
}
ThisPtr& operator = (const LPFOO foo) {
DebugMsg1( "ope = LPFOO" );
reset(foo);
return *this;
}
void reset(const LPFOO foo) {
clear();
if (foo == nullptr) {
return;
}
_ptr = foo;
REFMAP& m = refmap();
m[_ptr]++;
}
void copy(const ThisPtr& other) {
clear();
_ptr = other._ptr;
if (_ptr != nullptr) {
REFMAP& m = refmap();
if (m[_ptr]) {
m[_ptr]++;
} else {
// missing
_ptr = nullptr;
// or throw Exception
}
}
}
void clear() {
if (_ptr == nullptr) {
return;
}
REFMAP& m = refmap();
m[_ptr]--;
if (m[_ptr] == 0) {
ALLO allo;
allo.destroy(_ptr);
allo.deallocate(_ptr, 1);
}
_ptr = nullptr;
}
};
class Hoge
{
public:
Hoge() : id(counter()) {
Msg2( "Hoge() : ", id );
}
Hoge(const Hoge&) : id(counter()) {
Msg2( "Hoge(Hoge&) : ", id );
}
~Hoge() {
Msg2( "~Hoge() : ", id );
}
operator int () {
return id;
}
void print() {
Msg2( "Hoge method : ", id );
}
private:
const int id;
static int counter() {
static int c = 0;
return ++c;
}
};
FooPtr<Hoge> getHoge() {
FooPtr<Hoge> temp(new Hoge);
return temp;
}
int main() {
Msg1( "** begin of program **" );
FooPtr<Hoge> hoge1(new Hoge);
{
Msg1( "-- test 1 --" );
FooPtr<Hoge> empty;
empty = hoge1;
Msg2( "hoge1: ", *hoge1 );
Msg2( "empty: ", *empty );
}
{
Msg1( "-- test 2 --" );
FooPtr<Hoge> hoge2(hoge1);
Msg2( "hoge1: ", *hoge1 );
Msg2( "hoge2: ", *hoge2 );
}
{
Msg1( "-- test 3 --" );
FooPtr<Hoge> hoge3 = hoge1;
Msg2( "hoge1: ", *hoge1 );
Msg2( "hgoe3: ", *hoge3 );
}
{
Msg1( "-- test 4 --" );
FooPtr<Hoge> hoge4 = hoge1;
hoge1 = nullptr;
Msg2( "hoge4: ", *hoge4 );
}
{
Msg1( "-- test 5 --" );
hoge1 = new Hoge;
Msg2( "hoge1: ", *hoge1 );
}
{
Msg1( "-- test 6 --" );
hoge1->print();
}
{
Msg1( "-- test 7 --" );
getHoge();
hoge1 = getHoge();
}
{
Msg1( "-- test 8 --" );
Hoge *h1 = hoge1;
h1->print();
h1 = nullptr;
}
{
Msg1( "-- test 9 --" );
FooPtr<Hoge> f1(hoge1);
FooPtr<Hoge> f2(new Hoge);
if (f1 == hoge1) {
Msg1( "f1 == hoge1" );
} else {
Msg1( "not f1 == hoge1 (!?)" );
}
if (f2 != hoge1) {
Msg1( "f2 != hoge1" );
} else {
Msg1( "not f2 != hoge1 (!?)" );
}
}
{
Msg1( "-- test 10 --" );
FooPtr<Hoge> h3 = new Hoge;
hoge1 = h3;
}
Msg1( "** end of program **" );
return 0;
}