storing an instance of a class in an array

Started by
11 comments, last by DrPepperCorn 16 years, 10 months ago
Hi there. Ive posted before about somehing like this and was given an answer bt didnt really understand why this was happening. Ive just started to mess around with c++ again and come accross the same problem. Here is what ive done

	cEnemy * pEnemyArray = new cEnemy[2];
	cEnemy * a = new cEnemy;
	
	a		= NULL;
	pEnemyArray = NULL;
	peArray[0].SetName("SET NAME");

	delete a;
	delete [] pEnemyArray;


	//self checks
	if((a && pEnemyArray)== NULL)
	{
		cout << "pointers are NULL" << endl;
	}else
	{
		cout << "pointers are not null" <<endl;
	}


everything in the classes are working fine but i just cant sem to make an instance of a class eg Enemy 1 and then store this enemy in an array so later can pull this enemy out and have my player attack it. i keep getting a debugger error and a message saying system.NullreferenceException Object reference not set to an instance of an object. If you know why this is happenin can you explain it to me so i understand the fundamentals. If its just totally wrong someone please show and explain, i seriously have some trouble when trying to do this and i cant seem to research why im making this mistake. Ive done something like his in the past and didnt have this error . . bu then again ive not programmed for ages now and it may be something simple that i am overlooking. Thanks
Advertisement
I honestly can't really understand what you're trying to do by looking at the code. Just going by this:

Quote:
but i just cant sem to make an instance of a class eg Enemy 1 and then store this enemy in an array so later can pull this enemy out and have my player attack it.


I assume you need to store the enemy in an array of *pointers*:

CEnemy** pEnemyArray=new cEnemy*[2];
CEnemy* a=new CEnemy;

pEnemyArray[0]=a;

or better yet, use vectors.
so the double * is the answer

all im trying to do is make an enemy . . or an instance of 1 using my enemy class and stick it in an array. the array will hold say 5 enemys, when i kill ot i delete it from the array or FILO it and push it back on with increased stats (of course when i make my dynamic list, atm i just want to use a static array so i know for now exactly what bits got in it)

yes vectors are in my plan but when i hit this i really need to sort it out

so . . the double ** whats that mean then and why does that make it work (havent checked it yet tho)
Maybe a simple example will help.

First of all, a pointer is a variable designed to hold the address of another variable.

int* pInts[2]; // This is an array of 2 pointers to int.
int* pInt; // This is a pointer to int.

At this point all three pointers are uninitialized.
In other words they contain random addresses so to speak.
If we try to do anything with what they point to the program will typically crash.

pInt = new int;

The new keyword will ask the OS to find a free slot in memory and return the address of that slot back to our program. We catch that address in pInt.

Now pInt contain a valid address that we can do things to.
For example we can put the number 1 in that slot:
*pInt = 1;

We can copy that valid address into the first array element:
pInts[0] = pInt;

Now, pInts[0] contains the same valid address as pInt, and they can both be used to do things to our memory slot.

Then we put the address 0 into pInt:
pInt = NULL; // This does not change what pInt points to, it changes where pInt points!

Now pInt holds the address 0. 0 is not a valid address and if we try to do anything to what it points to, the program will probably crash again.
However, pInts[0] still holds our valid address, so we can still use that.

*pInts[0] = 2;

Now if we put address 0 into pInts[0]:
pInts[0] = 0; // Or NULL

Now both our pointers point to memory address 0 and they are both invalid.
At this point we have what is called a memory leak!
This is becouse we have lost the address that the OS gave us earlier, and there is no way for us to find out what it was.
As you probably understand a memory leak is a bad thing =)

Lets say we have a int variable called i:
int i;

If we want pInt to point to i's memory address we do:
pInt = &i;
If we do anything to what pInt points to now, we actually change i itself.
*pInt = 3;

One thing you do in your code is to delete a pointer that points to address 0.
This will again crash our program.

Does this make sense?
//self checksif((a && pEnemyArray)== NULL){	cout << "pointers are NULL" << endl;}else{	cout << "pointers are not null" <<endl;}

I doubt this is what you want to do.
If you want to make sure all the pointers is pointing at address 0
you must test all pointers separately:
//self checksif(a == NULL && pEnemyArray[0] == NULL && pEnemyArray[1] == NULL){	cout << "pointers are NULL" << endl;}else{	cout << "pointers are not null" <<endl;}
even that last one isn't quite right for making sure there are NO nulls going to be used, it needs to be

if(pointerA == 0 || pointerB == 0 || ...)
// some pointer is null
else
// no null pointers, do what you want safely now.

also, I recommend using something like:

typedef std::vector<cEnemy*> EnemyList;

then you get much cleaner syntax for allocation and size changes than with dynamic arrays, std::vector is a much easier class to use than dynamic arrays, ESPECIALLY if you get into multidimentional dynamic arrays.

and with vectors its easy to tell what levels are lists of things, and what levels are pointers and what levels are not.

using namespace std;
vector<cEnemy*>; // a list of enemies (using pointers)
vector<cEnemy>; // a list of enemies, not using pointers (not very usefull)
Quote:Original post by Xai
even that last one isn't quite right for making sure there are NO nulls going to be used, it needs to be

if(pointerA == 0 || pointerB == 0 || ...)
// some pointer is null
else
// no null pointers, do what you want safely now.


... Because of this, the original snippet actually works, though sort of accidentally.

(Hint: consider deMorgan's laws.)

Quote:
also, I recommend using something like:

typedef std::vector<cEnemy*> EnemyList;


Yes. Although I prefer to use the word 'Container' (thus EnemyContainer) for such typedefs, in order to speak more abstractly about what is actually there (i.e. not create an impression that std::list is being used).

Quote:then you get much cleaner syntax for allocation and size changes than with dynamic arrays, std::vector is a much easier class to use than dynamic arrays, ESPECIALLY if you get into multidimentional dynamic arrays.


Actually, multidimensional, rectangular dynamic arrays are better done with boost::multi_array. :)

Quote:vector<cEnemy>; // a list of enemies, not using pointers (not very usefull)


Disagreed. In simple cases (i.e. the class is default/copy-constructible, assignable and not polymorphic; and we are not sharing enemies between containers), holding them by value is just as useful, significantly simpler, highly likely to be better-performing, and more space-efficient.

Also, please ask yourself what the leading 'c' on the class name is telling that you don't already know (either from *looking* at the code, or from what your IDE and/or compiler can tell you). Is it worth the extra effort and ugliness?
Quote:Original post by DrPepperCornso . . the double ** whats that mean then and why does that make it work (havent checked it yet tho)


Because it's a pointer to a pointer(s) :)

You're initialising a pointer to an array object, which is holding pointers to your game objects.

For local multiplayer retro themed games, visit Domarius Games.

I may have misunderstood the point, but I interpreted the orignal code:

if(a & b == null)

as a somewhat improper attempt to test if ANY of the pointers is null, not a test to see if ALL the pointers are null (which is closer to what it actually does - but of course it doesnt do it correctly).

I may have been wrong, it was just an assumption on my part, because normally when I'm checking a set of pointers for null, its cause I want to know if they are safe to use, to run some algorithm that can't handle null, like

if(a != 0 || b != 0)
a = b;

or some such

so if the person wants

if()
// some pointer is null
else
// no pointer is null

my code is correct

and if they want

if()
// all pointers are null
else
// some pointer is not null

pulpfist's code is correct

the complication isn't with demorgan's law, but intent of the code.
woah. thanks guys, the error checking bit i did just as an after effect to check that my pointers were init to NULL, in fact at this point that was just old code.

Great stuff, i can always count on this site to clear one or two things up, just gonna plod now and may post back here if i un into any problems, saves me creating 50 topics here there and every where

This topic is closed to new replies.

Advertisement