Skip to main content
gamedev.net
🔒 Locked

Generic array manager

Started by Mr Cucumber 7 replies 650+ views
Original Post
Mr Cucumber
Mr Cucumber
I am trying to implement a generic array class in my program. What I want to do is this (I use C++): The class should have a pointer which I use to allocate the memory for the array. I have a member function CreateArray which takes two arguments, the number of elements in the array and the size in bytes per element. The class is called array, what I want to be able to do is something like this:
Array arr;
arr.CreateArray(5, sizeof(int));

arr[4] = 5;
arr[2] = 47; 
So the class should be able to handle all kinds of datatypes including my own classes. Is this possible and if so how? The inspiration for this came from the java class ArrayList
MadKeithV
MadKeithV
You should look into std::vector , it provides a nice wrapper around arrays.

It's only funny 'till someone gets hurt.And then it's just hilarious.Unless it's you.
Dave Hunt
Dave Hunt
You''ll have to use templates to accomplish this. Or you could just use the vector class/template from the STL.
CraZeE
CraZeE
not really being able to help much, but i think ur concept may (or may not) have a flaw. Using CreateArray(amount, size per element) probably wouldnt work. Correct me if i''m wrong but wouldnt using ''new'' require the data type itself to be specified?
Example:
int *array = new int[SIZE] 


the only few ways i see it possible would be to either use templates OR u''re probably only gonna use it for objects inherited from a common base class OR u''re gonna use a ''void'' pointer and perform ur own traversal. Its rather icky stuff imho.

But back to ur question, the array-like indexing for the object can be done easily coz the ''[]'' are treated as an operator too. you just need to overload the operator to get the indexing ability.
To learn, we share... Give some to take some -
Mr Cucumber
Mr Cucumber
Of course templates. Now why didnt I think of that.
But I get linking errors. THis is how I do it:


      //The class header looks like this:


template<class C> class Array

//I have a constructor and a destructor that are defined

//in the class like this:


Array(void);
~Array(void);

//They are later declared like this:


template<class C> Array<C>::Array(void)
{
}


template<class C> Array<C>::~Array(void)
{
}

//The only code I have in my main func is


Array<int> arr;


THis code compiles but gives me the following linking error:


  --------------------Configuration: ArrTest - Win32 Debug--------------------
Compiling...
Array.cpp
main.cpp
Linking...
main.obj : error LNK2001: unresolved external symbol "public: __thiscall Array<int>::~Array<int>(void)" (??1?$Array@H@@QAE@XZ)
main.obj : error LNK2001: unresolved external symbol "public: __thiscall Array<int>::Array<int>(void)" (??0?$Array@H@@QAE@XZ)
Debug/ArrTest.exe : fatal error LNK1120: 2 unresolved externals
Error executing link.exe.

ArrTest.exe - 3 error(s), 0 warning(s)


Any ideas whats wrong?



[edited by - Mr Cucumber on January 15, 2003 11:24:08 AM]
Qw3r7yU10p!
Qw3r7yU10p!
until your compiler supports the ''export'' keyword for templates (which only comeau does at the moment) you have to include the function definitions in the header so that they can be instantiated correctly.
IFooBar
IFooBar
quote:
Original post by Mr Cucumber
I am trying to implement a generic array class in my program.
What I want to do is this (I use C++):

The class should have a pointer which I use to allocate the memory for the array.
I have a member function CreateArray which takes two arguments, the number of elements in the array and the size in bytes per element.
The class is called array, what I want to be able to do is something like this:

Array arr;
arr.CreateArray(5, sizeof(int));

arr[4] = 5;
arr[2] = 47;


So the class should be able to handle all kinds of datatypes including my own classes.
Is this possible and if so how?
The inspiration for this came from the java class ArrayList


In the DirectX 9 SDK Microsoft has implemented something like this. Here''s the class incase you dont have the SDK.

  
//-----------------------------------------------------------------------------

// Name: ArrayListType

// Desc: Indicates how data should be stored in a CArrayList

//-----------------------------------------------------------------------------

enum ArrayListType
{
AL_VALUE, // entry data is copied into the list

AL_REFERENCE, // entry pointers are copied into the list

};


//-----------------------------------------------------------------------------

// Name: CArrayList

// Desc: A growable array

//-----------------------------------------------------------------------------

class CArrayList
{
protected:
ArrayListType m_ArrayListType;
void* m_pData;
UINT m_BytesPerEntry;
UINT m_NumEntries;
UINT m_NumEntriesAllocated;

public:
CArrayList( ArrayListType Type, UINT BytesPerEntry = 0 );
~CArrayList( void );
HRESULT Add( void* pEntry );
void Remove( UINT Entry );
void* GetPtr( UINT Entry );
UINT Count( void ) { return m_NumEntries; }
bool Contains( void* pEntryData );
void Clear( void ) { m_NumEntries = 0; }
};

...

  
//-----------------------------------------------------------------------------

// Name: CArrayList constructor

// Desc:

//-----------------------------------------------------------------------------

CArrayList::CArrayList( ArrayListType Type, UINT BytesPerEntry )
{
if( Type == AL_REFERENCE )
BytesPerEntry = sizeof(void*);
m_ArrayListType = Type;
m_pData = NULL;
m_BytesPerEntry = BytesPerEntry;
m_NumEntries = 0;
m_NumEntriesAllocated = 0;
}



//-----------------------------------------------------------------------------

// Name: CArrayList destructor

// Desc:

//-----------------------------------------------------------------------------

CArrayList::~CArrayList( void )
{
if( m_pData != NULL )
delete[] m_pData;
}




//-----------------------------------------------------------------------------

// Name: CArrayList::Add

// Desc: Adds pEntry to the list.

//-----------------------------------------------------------------------------

HRESULT CArrayList::Add( void* pEntry )
{
if( m_BytesPerEntry == 0 )
return E_FAIL;
if( m_pData == NULL || m_NumEntries + 1 > m_NumEntriesAllocated )
{
void* pDataNew;
UINT NumEntriesAllocatedNew;
if( m_NumEntriesAllocated == 0 )
NumEntriesAllocatedNew = 16;
else
NumEntriesAllocatedNew = m_NumEntriesAllocated * 2;
pDataNew = new BYTE[NumEntriesAllocatedNew * m_BytesPerEntry];
if( pDataNew == NULL )
return E_OUTOFMEMORY;
if( m_pData != NULL )
{
CopyMemory( pDataNew, m_pData, m_NumEntries * m_BytesPerEntry );
delete[] m_pData;
}
m_pData = pDataNew;
m_NumEntriesAllocated = NumEntriesAllocatedNew;
}

if( m_ArrayListType == AL_VALUE )
CopyMemory( (BYTE*)m_pData + (m_NumEntries * m_BytesPerEntry), pEntry, m_BytesPerEntry );
else
*(((void**)m_pData) + m_NumEntries) = pEntry;
m_NumEntries++;

return S_OK;
}




//-----------------------------------------------------------------------------

// Name: CArrayList::Remove

// Desc: Remove the item at Entry in the list, and collapse the array.

//-----------------------------------------------------------------------------

void CArrayList::Remove( UINT Entry )
{
// Decrement count

m_NumEntries--;

// Find the entry address

BYTE* pData = (BYTE*)m_pData + (Entry * m_BytesPerEntry);

// Collapse the array

MoveMemory( pData, pData + m_BytesPerEntry, ( m_NumEntries - Entry ) * m_BytesPerEntry );
}




//-----------------------------------------------------------------------------

// Name: CArrayList::GetPtr

// Desc: Returns a pointer to the Entry''th entry in the list.

//-----------------------------------------------------------------------------

void* CArrayList::GetPtr( UINT Entry )
{
if( m_ArrayListType == AL_VALUE )
return (BYTE*)m_pData + (Entry * m_BytesPerEntry);
else
return *(((void**)m_pData) + Entry);
}




//-----------------------------------------------------------------------------

// Name: CArrayList::Contains

// Desc: Returns whether the list contains an entry identical to the

// specified entry data.

//-----------------------------------------------------------------------------

bool CArrayList::Contains( void* pEntryData )
{
for( UINT iEntry = 0; iEntry < m_NumEntries; iEntry++ )
{
if( m_ArrayListType == AL_VALUE )
{
if( memcmp( GetPtr(iEntry), pEntryData, m_BytesPerEntry ) == 0 )
return true;
}
else
{
if( GetPtr(iEntry) == pEntryData )
return true;
}
}
return false;
}



:::Al:::
[Triple Buffer V2.0] - Resource leak imminent. Memory status: Fragile
[size=2]aliak.net
Teknofreek
Teknofreek
Yeah, templates are the way to go on this. Also, you should be able to overload the [] operator to get your assignment functions working well.

As an aside, you might want to check out that new book "Data Structures for Game Progammers" that''s featured on the main page here. I just picked it up this weekend and am really digging it so far. It goes over creating an array class, like the one you''re doing, as well as bit-arrays, multi-dimensional arrays, linked lists, trees, graphs, hash tables, sorting functions, etc.

I''ve only been through 5~6 chapters so far, but so far I''m loving it. It seems to do a pretty decent job of explaining why/how you want to set your things up so that they work well with memory caching and stuff, and there''s fancy little graphic demos of how the different data structures work....cool stuff for what''s probably usually a pretty dry topic to read about

-John
John

Topic Locked

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

Sign in to reply to this topic.