See what's going on with flipcode!




This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Common Templates: Singleton & Refcounter
  Submitted by



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!

Download Associated File: refcount.txt (6,836 bytes)

/*

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...


The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.