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.

| Bloat-free Typed Pointer Vector Class Submitted by

I'm not sure how many people already have this kind of thing going, but if not, it's never too late. I hate bloat in my code, and so I often used to use vector< void* > to store lists of objects. However, this adds the encumbrance of having to type cast whenever you want to use the object. Every vector< myobject* > can add about 1k of code to your app (my findings). I was initially going to do this with template specializations, but shortly after I learned about that I learned that VS.NET 7 doesn't have support for it. Anyway- It wasn't much work to rewrite most of the vector class. It's not exactly like <vector> but it should be similar enough that you can plug it right in and it should work with most of your code. One thing that will need fixing is the erase() function, which takes numeric indices instead of references to begin() and end(). I'm not 100% sure if it's bug free, but I use it throughout over 100k lines of code, and I know of none. This software is free for any use. You can contact me rogajin@hotmail.com

Currently browsing [bloatfreevec.zip] (1,948 bytes) - [pv.cpp] - (410 bytes)

    #include "stdafx.h"
    #include "pvect.h"

    class object
    {
    public:
    	object( int s )
    	{
    		a = s;
    	}
    	int a;
    	int b;
    };

    typedef pvect< object > ObjectVect;

    void test()
    {
    	ObjectVect ov;

    	ov.push_back( new object(1) );
    	ov.push_back( new object(2) );

    	// no more type casts
    	ov[0]->a = 10;

    	// will delete objects and clear array
    	ov.deleteall();
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
    	test();
    	return 0;
    }

Currently browsing [bloatfreevec.zip] (1,948 bytes) - [pvect.h] - (4,515 bytes)

    #pragma once
    // Pointer to <> classes, without neccessary compiler support for template
    // specialization

    #ifndef PVECT_DECL_SPEC
    #define PVECT_DECL_SPEC
    #endif

    #ifndef max
    #define max(a, b) ( (a) > (b) ? (a) : (b) )
    #define ownmax
    #endif

    #ifndef min
    #define min(a, b) ( (a) < (b) ? (a) : (b) )
    #define ownmin
    #endif

    class PVECT_DECL_SPEC pvoidvect
    {
    public:
    	// These data members are made public here so that the vector can be used as a plain array.
    	void** data;
    	int count;
    	int capacity;

    	pvoidvect(void)
    	{
    		count = 0;
    		capacity = 0;
    		data = NULL;
    	}
    	explicit pvoidvect(int _reserve)
    	{
    		count = 0;
    		capacity = 0;
    		data = NULL;
    		reserve(_reserve);
    	}

    	// copy constructor
    	pvoidvect(const pvoidvect& b)
    	{
    		data = NULL;
    		capacity = 0;
    		count = 0;
    		if (b.count > 0) {
    			reserve(b.count);
    			memcpy(data, b.data, sizeof(void*)*b.count);
    		}
    		count = b.count;
    	}

    	~pvoidvect(void)
    	{
    		if (data)
    			delete []data;
    	}
    	pvoidvect& operator=(const pvoidvect &b)
    	{
    		if (b.count > 0)
    		{
    			reserve(b.count);
    			memcpy(data, b.data, sizeof(void*)*b.count);
    		}
    		count = b.count;
    		return *this;
    	}

    	// safe set. Will resize if neccessary
    	void set(int pos, const void* a) {
    		if (pos >= count) {
    			// Do we need to resize, or can we just up our count?
    			if (pos >= capacity)
    				resize(pos+1);
    			else
    				count = pos+1;
    		}
    		data[pos] = const_cast<void*>(a);
    	}

    	void insert(int pos, const void* a)
    	{
    		if (pos >= capacity || count+1 > capacity)
    			reserve(max(capacity*2, pos+4));
    		//if (pos >= count)
    		//	count = pos+1;
    		int nmove = count - pos;
    		if (nmove > 0)
    			memmove(&(data[pos+1]), &(data[pos]), nmove*sizeof(void*));
    		data[pos] = const_cast<void*>(a);
    		count++;
    	}

    	void erase(int pos1, int pos2 = -1)
    	{
    		if (pos2 == -1)
    			pos2 = pos1;
    		int nmove = (count - pos2) - 1;
    		if (nmove > 0)
    			memmove(&(data[pos1]), &(data[pos2+1]), nmove*sizeof(void*));
    		count -= 1 + (pos2 - pos1);
    	}

    	// Grift....
    	void* pop_back()
    	{
    		if (count > 0)
    			count--;
    		return data[count];
    	}

    	void push_back(const void* a)
    	{
    		if (count >= capacity)
    			reserve(capacity*2);
    		data[count++] = const_cast<void*>(a);
    	}
    	const void* operator[](int i) const
    	{
    		return data[i];
    	}

    	void*& operator[](int i)
    	{
    		return data[i];
    	}
    	//void*& v(int i) {
    	//	return data[i];
    	//}

    	void* back() const
    	{
    		return data[count-1];
    	}
    	void*& back()
    	{
    		return data[count-1];
    	}

    	// returns -1 on failure
    	int find( const void* t ) const
    	{
    		for (int i = 0; i < count; i++)
    			if (data[i] == t) return i;
    		return -1;
    	}

    	void clear()
    	{
    		if (data)
    			delete []data;
    		data = NULL;
    		count = 0;
    		capacity = 0;
    	}
    	int size() const
    	{
    		return count;
    	}
    	// preserves existing entities but doesn't set count
    	void reserve(int newsize)
    	{
    		int oc = count;
    		resize(max(newsize, count));
    		count = oc;
    	}
    	// preserves existing entities and sets count to newsize
    	void resize(int newsize)
    	{
    		int ocount = count;
    		count = newsize;
    		if (newsize == 0) newsize = 2;
    		void** nd = new void*[newsize];
    		if (ocount > 0)
    			memcpy(nd, data, sizeof(void*)*min(ocount, newsize));
    		if (data)
    			delete []data;
    		data = nd;
    		capacity = newsize;
    	}
    };

    template < class T > class PVECT_DECL_SPEC pvect : public pvoidvect
    {
    public:
    	typedef pvoidvect Base;

    	pvect() : Base() {}

    	explicit pvect(int reserve) : Base(reserve) {}

    	pvect(const pvect& b) : Base(b) {}

    	pvect& operator=(const pvect &b) { return (pvect&) Base::operator=(b); }

    	void set(int pos, const T* a) { Base::set(pos,a); }

    	void insert(int pos, const T* a) { Base::insert(pos, a); }

    	void erase(int pos1, int pos2 = -1) { Base::erase(pos1, pos2); }

    	T* pop_back() { return static_cast<T*>(Base::pop_back()); }

    	void push_back(const T* a) { Base::push_back(a); }

    	const T* operator[](int i) const { return static_cast<const T*>(Base::operator[](i)); }

    	T*& operator[](int i) { return (T*&) Base::operator[](i); }

    	//T*& operator[](int i) { return static_cast<T*&>( Base::v(i) ); }

    	T* back() const { return static_cast<T*>(Base::back()); }

    	int find( const T* a ) const { return Base::find(a); }

    	void clear() { Base::clear(); }

    	void deleteall()
    	{
    		for (int i = 0; i < count; i++)
    			delete static_cast<T*>( data[i] );
    		clear();
    	}

    	int size() const { return Base::size(); }

    	void reserve(int newsize) { Base::reserve(newsize); }

    	void resize(int newsize) { Base::resize(newsize); }
    };

    #ifdef ownmax
    #undef max
    #undef ownmax
    #endif

    #ifdef ownmin
    #undef min
    #undef ownmin
    #endif

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.