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.

 

  Smart Pointers
  Submitted by



Smart pointers are special template classes that wraps access to normal pointer. Combined with simple reference counting scheme they become powerfull tool for managing object's lifetime. They are most usefull when used in combination with templated containers, like ones in STL. There are some tough issues with smart pointers and reference counting itself, but i think thier advantages by far overcome thier weak points.

There`s another type of smart pointer which i call Singleton Pointer, it more like template curiosity but i like using it. SingletonPointer simplify access to singlteon classes, if you have Engine class singleton, then instead of writing everytime you want to access Engine instance Engine::instance()->blahblah(); you can define variable: SingletonPtr gEngine; and use gEngine->blahblah()

Currently browsing [smartptr.zip] (2,458 bytes) - [example.cpp] - (1,331 bytes)

#include <stdio.h>
#include <vector>
#include "sptr.h"

using namespace std;

class Texture : public Base { public: Texture() { static int counter = 0; id = counter++; printf( "Texture N%d created\n",id ); } virtual ~Texture() { printf( "Texture N%d destroyed\n",id ); } private: int id; };

class Material : public Base { public: Material() { // Allocate texture. m_texture = new Texture; }

// Set/Get texture pointer. void texture( Texture *tex ) { m_texture = tex; } // Release old texture, AddRef new texture. Texture* texture() const { return m_texture; } private: smart_ptr<Texture> m_texture; };

void main() { typedef vector<smart_ptr<Material> > Materials; Materials materials;

// Create some materials and put them in array. materials.push_back( new Material ); materials.push_back( new Material );

Material *mat1 = new Material; Material *mat2 = new Material; Texture *tex = new Texture; // Set new texture for mat1, original texture of mat1 destroyed. mat1->texture( tex );

// Share texture from mat1, original texture of mat2 destroyed, tex have refCount = 2. mat2->texture( mat1->texture() );

materials.push_back( mat1 ); materials.push_back( mat2 );

// Deallocate all materials and textures. materials.clear(); }

Currently browsing [smartptr.zip] (2,458 bytes) - [singletonptr.h] - (491 bytes)

// SingletonPtr is a wraper class that encapsulate all singleton access.
// T must be Singleton class.
template <class T>
class SingletonPtr {
public:
	operator bool() const { return T::instance() != NULL; };
	bool  operator !() const { return T::instance() == NULL; };

operator T*() const { return T::instance(); } operator const T*() const { return T::instance(); } T& operator*() const { return *T::instance(); } T* operator->(void) const { return T::instance(); } };

Currently browsing [smartptr.zip] (2,458 bytes) - [sptr.h] - (3,065 bytes)


class Base {
public:
  virtual ~Base() {};

void AddRef() { m_refCount++; }; void Release() { if (--m_refCount <= 0) delete this; };

protected: // Abstract class constructor must be protected to prevent direct instantiation. Base() : m_refCount(0) {};

private: // For safety. Base( const Base &b ) {}; Base& operator=( const Base &b ) {};

int m_refCount; // Reference counter. };

// Smart pointer wraper class that implements reference counting using Base class. template <class T> class smart_ptr { T* p; public: smart_ptr() : p(NULL) {} smart_ptr( T* p_ ) : p(p_) { if (p) p->AddRef(); } smart_ptr( const smart_ptr<T>& p_ ) : p(p_.p) { if (p) p->AddRef(); } // Copy constructor. smart_ptr( int Null ) : p(NULL) {} // Assignment to NULL ~smart_ptr() { if (p) p->Release(); }

// Casting to normal pointer. operator T*() const { return p; }

// Casting to const pointer. operator const T*() const { return p; } // Dereference operator, allow dereferencing smart pointer just like normal pointer. T& operator*() const { return *p; }

// Arrow operator, allow to use regular C syntax to access members of class. T* operator->(void) const { return p; } // Replace pointer. smart_ptr& operator=( T* newp ) { if (newp) newp->AddRef(); if (p) p->Release(); p = newp; return *this; }

// Replace pointer. smart_ptr& operator=( const smart_ptr<T> &newp ) { if (newp.p) newp.p->AddRef(); if (p) p->Release(); p = newp.p; return *this; } // Cast to boolean, simplify if statements with smart pointers. operator bool() { return p != NULL; }; operator bool() const { return p != NULL; }; bool operator !() { return p == NULL; };

// Misc compare functions. bool operator == ( const T* p1 ) const { return p == p1; }; bool operator != ( const T* p1 ) const { return p != p1; }; bool operator < ( const T* p1 ) const { return p < p1; }; bool operator > ( const T* p1 ) const { return p > p1; }; bool operator == ( const smart_ptr<T> &p1 ) const { return p == p1.p; }; bool operator != ( const smart_ptr<T> &p1 ) const { return p != p1.p; }; bool operator < ( const smart_ptr<T> &p1 ) const { return p < p1.p; }; bool operator > ( const smart_ptr<T> &p1 ) const { return p > p1.p; };

friend bool operator == ( const smart_ptr<T> &p1,int null ); friend bool operator != ( const smart_ptr<T> &p1,int null ); friend bool operator == ( int null,const smart_ptr<T> &p1 ); friend bool operator != ( int null,const smart_ptr<T> &p1 ); };

template <class T> inline bool operator == ( const smart_ptr<T> &p1,int null ) { return p1.p == 0; }

template <class T> inline bool operator != ( const smart_ptr<T> &p1,int null ) { return p1.p != 0; }

template <class T> inline bool operator == ( int null,const smart_ptr<T> &p1 ) { return p1.p == 0; }

template <class T> inline bool operator != ( int null,const smart_ptr<T> &p1 ) { return p1.p != 0; }


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.