Skip to main content
GameDev.net gamedev.net
🔒 Locked

Dynamic array of std::string

Started by jake_Ghost Jun 19, 2010 at 3:32 PM 9 replies 4.2k views
Original Post
jake_Ghost
jake_Ghost
I have written a small array class to handle dynamic arrays of objects. I did it mostly for speed. But I am running into problems with memcpy and std::string.

I use a function called adjust pointer which just allocates a new array, copies the old one into it and deletes the old one.

template <class T> void cGhost :: AdjustPointer(T *&Var, int &Size, int Increment){	if (Increment < 0)	{		if (Size + Increment < 1)		{			if (Var == NULL)				return;			else			{				SAFE_DELETE_ARRAY(Var);				Size = 0;				return;			}		}	}	T *New = new T[Size + Increment];	memcpy(&New[0], &Var[0], sizeof(T) * Size);	SAFE_DELETE_ARRAY(Var);	Var = New;	Size += Increment;}


But I am running into problems with strings. It doesn't seem to copy properly and I ended up having to use a for loop and set each iteration directly. I'm guessing it has something to do with the how the string stores it array of chars. Maybe a copy constructor is needed with strings? I'm not sure. I've spent a long time looking up this problem and I can't seem to find any solution.

Here's the array class for reference.

#pragma once#include "GhostVars.h"template<class T>class cArray{public:	cArray(void)	{		Array = NULL;		Size = 0;		Increment = 1;		Last = 0;		CurIndex = 0;		AutoDelete = true;	}	cArray(int size, int inc = 1, bool autodelete = true)	{		Array = NULL;		Size = 0;		Increment = inc;		Last = 0;		CurIndex = 0;		AutoDelete = autodelete;		Increase(size);	}	cArray(const cArray &cA)	{		Array = cA.Array;		Size = cA.Size;		Increment = cA.Increment;		Last = cA.Last;		CurIndex = cA.CurIndex;		AutoDelete = cA.AutoDelete;	}	~cArray(void)	{		if (AutoDelete) 			SAFE_DELETE_ARRAY(Array);	}	void Insert(const T &In, const int &Index);	void Delete(const int &Index);		void InsertSafe(const T &In, const int &Index);	void DeleteSafe(const int &Index);	__inline void Clear() { if (Size > 0) { SAFE_DELETE_ARRAY(Array); Size = 0; } }	__inline T& operator[](const int &Index) { return Array[Index]; }	__inline T *Get(const int &Index) { return &Array[Index]; }	__inline T *GetFirst() { return &Array[0]; }	__inline T *GetLast() { return &Array[Last]; }	__inline bool GetSafe(T &Out, const int &Index) { if (Index >= 0 && Index < Size) { Out = Array[Index]; return true; } else return false; }	__inline bool GetSafeFirst(T &Out) { if (Size > 0) { Out = Array[0]; return true; } else return false; }	__inline bool GetSafeLast(T &Out) { if (Size > 0) { Out = Array[Last]; return true; } else return false; }	__inline const int &GetSize() { return Size; }	__inline const int &GetIncrement() { return Increment; }	__inline const int &GetFilledSize() { return CurIndex; }	__inline void operator++() { Ghost->AdjustPointer(Array, Size, 1); Last = Size - 1; }	__inline void operator--() { Ghost->AdjustPointer(Array, Size, -1); Last = Size - 1; }	__inline void Increase(int inc = 0) { if (inc == 0) inc = Increment; Ghost->AdjustPointer(Array, Size, inc); Last = Size - 1;}	__inline void Decrease(int inc = 0) { if (inc == 0) inc = -Increment; Ghost->AdjustPointer(Array, Size, inc); Last = Size - 1;}	__inline void Push(const T &In) { Ghost->AdjustPointer(Array, Size, 1); Last = Size - 1; Array[Last] = In; }	__inline void Fill(const T &In) { Array[CurIndex] = In; ++CurIndex;  if (CurIndex >= Size) Increase(); }	__inline bool IsValidIndex(const int &Index) { return (Index >= 0 && Index < Size); }	__inline void SetAutoDelete(const bool &In) { AutoDelete = In; }	__inline void SetIncrement(const int &i) { if (i != 0) Increment = i; }	__inline void SetCurIndex(const int &i = 0) { if (IsValidIndex(i)) CurIndex = i; }private:	T *Array;	int Size;	int Increment;	int Last;	int CurIndex;	bool AutoDelete;};template<class T> void cArray<T> :: Insert(const T &In, const int &Index){	T *NewArray = new T[Size + 1];	memcpy(&NewArray[0], &Array[0], sizeof(T) * Index);	NewArray[Index] = In;	memcpy(&NewArray[Index + 1], &Array[Index], sizeof(T) * Size - Index);	SAFE_DELETE_ARRAY(Array);	Array = NewArray;	++Size;}template<class T> void cArray<T> :: Delete(const int &Index){	if (Size == 1)	{		SAFE_DELETE_ARRAY(Array);		Size = 0;		return;	}	--Size;	T *NewArray = new T[Size];	if (Index != 0 && Index < Size)	{		memcpy(&NewArray[0], &Array[0], sizeof(T) * Index);		memcpy(&NewArray[Index], &Array[Index + 1], sizeof(T) * (Size - Index));	}	else if (Index == 0)		memcpy(&NewArray[0], &Array[1], sizeof(T) * (Size));	else if (Index == Size)		memcpy(&NewArray[0], &Array[0], sizeof(T) * (Size));	SAFE_DELETE_ARRAY(Array);	Array = NewArray;}template<class T> void cArray<T> :: InsertSafe(const T &In, const int &Index){	if (Index >= 0 && Index < Size)	{		T *NewArray = new T[Size + 1];		memcpy(&NewArray[0], &Array[0], sizeof(T) * Index);		NewArray[Index] = In;		memcpy(&NewArray[Index + 1], &Array[Index], sizeof(T) * Size - Index);		SAFE_DELETE_ARRAY(Array);		Array = NewArray;		++Size;	}}template<class T> void cArray<T> :: DeleteSafe(const int &Index){	if (Index >= 0 && Index < Size)	{		if (Size == 1)		{			SAFE_DELETE_ARRAY(Array);			Size = 0;			return;		}		--Size;		T *NewArray = new T[Size];		if (Index != 0 && Index < Size)		{			memcpy(&NewArray[0], &Array[0], sizeof(T) * Index);			memcpy(&NewArray[Index], &Array[Index + 1], sizeof(T) * (Size - Index));		}		else if (Index == 0)			memcpy(&NewArray[0], &Array[1], sizeof(T) * (Size));		else if (Index == Size)			memcpy(&NewArray[0], &Array[0], sizeof(T) * (Size));		SAFE_DELETE_ARRAY(Array);		Array = NewArray;	}}


Any help would be great!

Thanks,
Jake
bubu LV
bubu LV
Don't use memcpy. Use std::copy like this:
std::copy(Var, Var + Size, New);


In general - you are not allowed to use memcpy with non-POD structs/classes.
jake_Ghost
jake_Ghost
Thank you so much!! Why didn't I think of that... :D
fastcall22
fastcall22
Is there any reason why you're not using the standard dynamic array, std::vector? The STL library has been thoroughly tested and debugged by millions of developers, while your custom dynamic array, may end up being slower, more buggy, and less efficient, if not as fast and as efficient as the STL's own containers. For instance, your array class re-allocates and copies all of the elements into an array of a different size for every time you add an element to the array or remove an element from the array.
jake_Ghost
jake_Ghost
I found that vectors are not so fast when not using iterators. Using the [] operator is very slow. But maybe I am doing something wrong? I also wrote this class as a learning experience. I find that writing my own class helps me understand things better.
fastcall22
fastcall22
Quote:
Original post by jake_Ghost
I found that vectors are not so fast when not using iterators. Using the [] operator is very slow. But maybe I am doing something wrong?


Depends. Did you compile your project in with or without optimizations? A vector is basically a raw array with optimizations.

Quote:
I also wrote this class as a learning experience. I find that writing my own class helps me understand things better.


That's ok. Just don't use it for production code.
jake_Ghost
jake_Ghost
I use optimizations for the release version. Using iterators with vectors is as fast as a normal array it just requires more code to use it. Would it be a good idea to write a wrapper class that handles all the iterators to vectors to increase performance?

I did a lot of testing with vectors when I was writing my particle system and I found that they were just too slow, even when using iterators and pointers to each memory block.

What would you suggest I do?
SiCrane
SiCrane
Are you using MSVC? If so then it could be that your release code still has the security checks in it.
jake_Ghost
jake_Ghost
I am, maybe that is the cause of the problems.
Antheus
Antheus
Your version has n^2 insert performance.
Decrius
Decrius
Quote:
Original post by jake_Ghost
I found that vectors are not so fast when not using iterators. Using the [] operator is very slow. But maybe I am doing something wrong?


You sure? Using an iterator or the random-access operator shouldn't matter. Even so, in debug mode the iterator method often is slower. The [N] operator basically takes &vector.begin() and adds N * sizeof(element) to that pointer. In a release build neither of both should outperform one-another.

Quote:
Original post by jake_Ghost I also wrote this class as a learning experience. I find that writing my own class helps me understand things better.


Do this more often! It's the best way to learn the language thoroughly and get a broad and view and interest on matters! There are many production programmers here, but as an indie developer I really enjoy figuring out how techniques work.
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.