/*
Editor's note:
COTD Entry: Common Templates: Singleton & Refcounter by Konstantin Mikheev [fowrel@mailru.com]
Few days ago I had found (in MSDN ;-) simple template for reference
counting. With some changes it works without bugs. ;-)
(Copy constructor was added and trickyness was improved by adding default
constructor and NULL checking.)
I was wondered why doesn't programmers uses such useful things like
this refecence counting templates.
So that's my sources with sample. 8)
It also includes singleton template wich is useful for... for singletones! ;-))
With little changings of Your code it will do a lots of work for You. ;-)
And You'll never think about memory leaks with this refcounting!
*/
////////////////////////////////////////////////////////////////////////////////
// Permission: You can use this source code in any way.
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// urefcounter
// A base class for reference-counter enabled classes.
// Rules:
// 1. All child classes MUST be initialized with new.
// 2. Child classes MUST NOT be destroyed by delete.
////////////////////////////////////////////////////////////////////////////////
class urefcounter
{
public:
void upcount()
{
mcounter++;
}
void downcount()
{
if (!--mcounter)
delete this;
}
protected:
urefcounter() : mcounter(0) {}
virtual ~urefcounter() {}
private:
uint mcounter;
private: // Dumb operations. urefcounter can't be copied.
urefcounter &operator = (const urefcounter &);
urefcounter(const urefcounter &);
};
////////////////////////////////////////////////////////////////////////////////
// uref
// Class that provides automatic counting mechanism for urefcounter class.
// Use it instead of usuall pointers for urefcounter's child classes.
////////////////////////////////////////////////////////////////////////////////
template <class refcounter>
class uref
{
public:
uref() : mobject(unull) {}
uref(refcounter *object) : mobject(object)
{
if (mobject)
mobject->upcount();
}
uref(const uref &other) : mobject(other.mobject)
{
if (mobject)
mobject->upcount();
}
~uref()
{
if (mobject)
mobject->downcount();
}
operator refcounter *()
{
return mobject;
}
refcounter *operator ->()
{
return mobject;
}
refcounter &operator *()
{
return *mobject;
}
uref &operator = (refcounter *other)
{
if (mobject)
mobject->downcount();
mobject = other;
if (mobject)
mobject->upcount();
return *this;
}
uref &operator = (const uref &other)
{
return operator = (other.mobject);
}
private:
refcounter *mobject;
};
////////////////////////////////////////////////////////////////////////////////
// Sample of using this template:
////////////////////////////////////////////////////////////////////////////////
class testmem : public urefcounter
{
public:
typedef uref<testmem> ref; // defining it here so tricky!!!
public:
testmem()
{
id = idmax++;
cout << id << " - testmem::testmem()" << endl;
}
~testmem()
{
cout << id << " - testmem::~testmem()" << endl;
}
testmem &operator = (const testmem &other)
{
cout << id << " - testmem::operator = (const testmem &other)"
<< endl;
return *this;
}
testmem(const testmem &other)
{
id = idmax++;
cout << id << " - testmem::testmem(const testmem &other)"
<< endl;
*this = other;
}
void test()
{
cout << id << " - testmem::test" << endl;
}
private:
int id;
static int idmax;
};
int testmem::idmax = 0;
int main(int argc, char* argv[])
{
vector<testmem::ref> refs;
testmem::ref test = new testmem;
refs.push_back(test);
refs.push_back(test);
refs.push_back(test);
refs.push_back(new testmem);
test->test();
for (vector<testmem::ref>::size_type i = 0; i < refs.size(); i++)
{
refs[i]->test();
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
// Output:
// 0 - testmem::testmem()
// 1 - testmem::testmem()
// 0 - testmem::test
// 0 - testmem::test
// 0 - testmem::test
// 0 - testmem::test
// 1 - testmem::test
// 1 - testmem::~testmem()
// 0 - testmem::~testmem()
////////////////////////////////////////////////////////////////////////////////
// "Congratulations! No memory leaks found!"
// -- Paul Nettle's mmgr. ;-)
0. The main purpose using uref/urefcounter is that You mustn't care about
calling delete and don't worry about strict objects owning scheme.
1. If You change uref's upcount() to AddRef() and downcount() to Release()
then You'll get a perfect container for COM interfaces.
2. Assigning NULL to variable of type uref<blablabla> will cause call downcount
for blablabla object. ;-)
Sample:
EeTexture::ref texture = Graphics->CreateFromFile(texturefilename);
texture = NULL;
will cause receive texture's interface and then downcounting of it's counter.
(Another assignment NULL to texture will do nothing until texture initialized
again.)
3. You can test if pointer is valid only by comparsion uref object with NULL.
This tricky because when uref intitialized with default constructor it
contains NULL pointer.
////////////////////////////////////////////////////////////////////////////////
// usingleton
// A base class for all singletones. Generates
// throw usingleton<singleton_class>::exception()
// on duplication.
// Use it like:
//
// class singleton_class : private usingleton<singleton_class>
// {
// blablabla...
// };
////////////////////////////////////////////////////////////////////////////////
template <class t>
class usingleton
{
public:
class exception {};
usingleton()
{
if (instance != unull)
throw exception();
instance = (t *)this;
}
~usingleton()
{
instance = unull;
}
static t *singleton()
{
return instance;
}
private:
static t *instance;
private: // dumb operations
usingleton &operator = (const usingleton &);
usingleton(const usingleton &);
};
template <class t>
t *usingleton<t>::instance = unull;
0. You can hide singleton() property without any other affection of usingleton
functionality by declaring it as private. Do this (in most cases) if You not
sure that objects uses Your singleton class only after it has been initialized.
1. ...a final tip: You can use urefcounter and usingleton together!!!
Why? Can't imagine...
|