Yello, could someone enlighten me as to the pros and cons of holding a pointer to an object in an array vs holding an int index to it?
For example if I had a vector of employees and a vector of ranks. If I wanted to access the rank data of a certain employee, would it be best for the employee class to store a pointer to that rank object, so I can use "employee.rank->title", or an index to use "ranks.at( employee.rank ).title"? Are there are design problems I would encounter or inefficiencies with either method? Or maybe theres an entirely different and better way to do it that I've missed.
Thanks.
Problem with the pointer approach: whenever the vector grows, all pointers to its elements become invalid.
Problem with the index approach: when you delete an employee, a large number of indexes become invalid.
A solution is to use shared_ptr for both employee::rank and for the contents of the vectors.
Since you're using a pointer to a rank object as a member of your employee class, then I guess I'm missing out on the reason for the outside vector in the first place. Any sample code to clarify what you're trying to do?
Depending on what you're doing, is it possible a std::map might work better? It's a simple one-to-one correlation. You're trying to look up the rank object by specifying the employee object, right?
Well, to go into more detail, what I'm actually doing is for a game. A unit would contain a pointer or index to the unit type so as to keep memory usage low, only keeping things like health in itself. When the unit needs it's stats, it goes through that pointer/index. The unit type container would never change after the data had been loaded so invalidation isn't a problem I don't think, though I'll look into shared_ptr.
A map would mean an instance of a unit type could only be used by one unit wouldn't it? Maybe a multimap would work, I've never used one so I don't know. Would that be a better form of index? I realise it probably doesn't matter much which way I choose, it's probably not even that much memory, but I'm somewhat of a perfectionist and also sick of noticing that I did something fundamentally wrong at the start and have change a load of stuff.
You've got several "unit" objects, and each one is supposed to store a pointer to a "unit type" object, which describes statistics about the "unit" object and/or other instances of "unit" objects with that same specific type?
Kinda like this?
1 2 3 4 5 6 7 8 9 10 11
class Unit
{
private:
int m_nHealth; //Health
UnitType *m_pUnitType; //Pointer to object with information about the unit type?
//... other members ...
public:
//... constructor(s), destructors, other methods, etc ...
};
As in, several "Unit" objects would be able to point to one instance of a "UnitType" object, and then several other "Unit" objects would point to a different instance "UnitType" with different values - and each different "UnitType" object would only be created once?
If that's the case, there may be a cleaner way to do this (using polymorphism and possibly static members), so tell me if I'm close - or way off - on my assumptions above.
A unit would contain a pointer or index to the unit type so as to keep memory usage low, only keeping things like health in itself. When the unit needs it's stats, it goes through that pointer/index.
From an OOP perspective, it's better to use a pointer:
You want to keep objects as "stupid" as possible. Make them as ignorant of the outside world as possible. This keeps code simpler and makes it more reusable and adaptable to change.
Using an index demands two things:
1) it demands you have a random access array somewhere else in your program
2) it demands that your object be aware of and have access to that array.
This array is part of the "outside world" that this class should know nothing about. This Unit class should only know how to be a Unit, and how to do things that Units do. It should not need to know how different Units are stored by the rest of the program. That's too broad of scope.
Okay, so going further with this... let's use tanks as an example - maybe that's actually what you're using? Or maybe some kind of machine guns? Anyway, just an example here...
Let's say you have two types of tanks. My impression is that you'd have all enemy tanks display one bitmap, and all the ally tanks would display another (like allies would be green and enemies are the same image, but red - that sort of thing). The guns on the enemy tanks are in front, but those on the allies' tanks are in the center. And then the ally tanks rotate at a rate of 5 degrees/sec, while the enemy tanks rotate at 7 degrees/sec. This requires the same variables, but with different values for allies and enemies.
So then since you're using the same bitmap and other values for all enemy tanks, for example, it makes no sense to have multiple copies of all that data in memory, right? And all those values are what you wish to store in your "unit type" information object?
The above is just a typical scenario that I envision. If this is pretty close, let me/us know - you'll simply be using polymorphism and some statics, from what I can gather.
That is indeed the scenario, except I'm doing it with planes, and models. So the allies could use Spitfire, P-38, Hurricane, etc. while the other guys have Bf-109, Zero, FW-190 etc. They're loaded from human readable files so it can be edited easily and have models added.
class UnitType
{
//...class definition...
};
class BaseUnit
{
protected:
virtual UnitType& getUnitType() = 0;
//void draw();
//...other methods all derived types share...
};
class AllyUnit : public BaseUnit
{
private:
static UnitType m_unitType;
protected:
virtual UnitType& getUnitType()
{
return m_unitType;
}
};
UnitType AllyUnit::m_unitType;
class EnemyUnit : public BaseUnit
{
private:
static UnitType m_unitType;
protected:
virtual UnitType& getUnitType()
{
return m_unitType;
}
};
UnitType EnemyUnit::m_unitType;
This avoids the problem of having an outside container, because each derived class contains its own distinct static member which persists for the life of the application. The classes all still implement identical interfaces.
Now, inside your draw() method, and whatever other methods you call for each object, you just call the object's "getUnitType()" method to get a reference to the static UnitType member. For example, if the UnitType class has a member "m_gunPlacement", you'd just call "getUnitType().getGunPlacement()" or something similar, and you'd get a different result for each type, but the same result for each instance of that type.
And by keeping the UnitType member private, but having protected access to it and using public inheritance, you may continue to derive subclasses as much as you wish: