When to point to an object vs. hold it directly in a variable

Started by
4 comments, last by wqking 12 years, 2 months ago
I know that there are two ways to "store" an object in C++:


// using a variable
Car myCar;
myCar.drive();

// using a pointer
Car *myCarPointer = new Car();
myCarPointer->drive();
delete myCarPointer;


The second method is the way you would do it in C# or Java (minus the manual deletion), but both are valid in C++. The book I use (C++ Programming in Easy Steps) doesn't outline the difference other than that it looks like you can do something like this with a derived class:


BaseClass *object = new DerivedClass();


In the context of a game, when would you want to use one over the other?

"So there you have it, ladies and gentlemen: the only API I’ve ever used that requires both elevated privileges and a dedicated user thread just to copy a block of structures from the kernel to the user." - Casey Muratori

boreal.aggydaggy.com

Advertisement
Several Reasons:

1) Object lifetime
With Car myCar the object lives until it falls out of scope. myCar is allocated on the stack which may be faster if not as fast than a allocation from the heap. If the object needs to live longer than the scope it belongs to, then it must be allocated on the heap, where the object must be destroyed manually with delete.

2) Which-object
A pointer or reference can describe "which object". A pointer must be used to retreive something from the heap, though a pointer doesn't necessarily need to point to a dynamically allocated object:

Car hisCar; // stack
Car* myCar = new Car; // heap

Car* whichCar = (rand() & 0x08) ? &hisCar : myCar; // pointer on stack, may point to stack or heap
Car& anotherCar = (rand() & 0x08) ? hisCar : *myCar; // anotherCar "is" either "hisCar" or "myCar"

whichCar->drive();
anotherCar.drive();

whichCar = 0; // or NULL or nullptr

delete myCar;


3) Interfaces
In the case of games, one can use inheritance to generalize a lot of game objects:


class Entity {
public:
virtual ~Entity() { }
virtual void update() = 0;
virtual void render() = 0;
};

class Player : public Entity {
public:
void update() {
cout << "Player::update()\n";
}
void render() {
cout << "Player::render()\n";
}
};
class Monster : public Entity {
public:
void update() {
cout << "Monster::update()\n";
}
void render() {
cout << "Monster::render()\n";
}
};

int main() {
Player thePlayer;
Monster aMonster;
Monster* others[2] = { new Monster, new Monster };

Entity* ents[4] = {
&thePlayer, aMonster, others[0], others[1]
};

for ( int i = 0; i < 4; ++i ) {
ents->update();
ents->render();
}

delete others[0];
delete others[1];
}


Hope this helps.

Additional reading:
http://www.parashift.com/c++-faq-lite/references.html
http://www.parashift.com/c++-faq-lite/basics-of-inheritance.html
http://www.parashift.com/c++-faq-lite/freestore-mgmt.html

I know that there are two ways to "store" an object in C++:


// using a variable
Car myCar;
myCar.drive();

// using a pointer
Car *myCarPointer = new Car();
myCarPointer->drive();
delete myCarPointer;


The second method is the way you would do it in C# or Java (minus the manual deletion), but both are valid in C++. The book I use (C++ Programming in Easy Steps) doesn't outline the difference other than that it looks like you can do something like this with a derived class:


BaseClass *object = new DerivedClass();


In the context of a game, when would you want to use one over the other?


There are two big differences:
1) Things you allocate with new will be allocated on the heap (normally) (things created the first way ends up on the stack), the stack is normally faster but stack space is limited.
2) Multiple pointers can point to the same object (So if you are going to share one object between multiple other objects then pointers are good, allthough you could still allocate the object in question on the stack).

a few generic rules you can follow if you want:
* allocate small or short lived objects on the stack.
* allocate large objects on the heap
* don't use raw pointers (unique_ptr and shared_ptr are much better option in most cases),

so rather than
Class *obj = new Class()
....
delete obj;

you do

shared_ptr<Class> obj(new Class())
shared_ptr<Class> obj2(obj);
code
no need to delete, its handled automatically and if you have multiple shared pointers to the same object(i made 2 in the example) the deletion will happen when all shared pointer have gone out of scope. unique_ptr works in the same way except it cannot be copied (like i did with the shared pointer) and thus doesn't have to count references (as you can only have one unique_ptr to each object that object gets deleted as soon as the unique_ptr goes out of scope)
[size="1"]I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

a few generic rules you can follow if you want:


[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

* allocate small or short lived objects on the stack.[/font]


[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

* allocate large objects on the heap[/font]


[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

* don't use raw pointers (unique_ptr and shared_ptr are much better option in most cases),[/quote][/font]


[color=#282828][font=helvetica, arial, verdana, tahoma, sans-serif]

Perfect, thanks![/font]



If I was to make a vector of Entities, I would do something like this, right?


// create
vector<Entity> *entities;
entities->push_back(new Player());

// update
for(int i = 0; i < entities.size(); i++)
entities->update();

// delete
int s = entities.size(); //
for(int i = 0; i < s; i++) // redundant?
delete entities; //
delete entities;

"So there you have it, ladies and gentlemen: the only API I’ve ever used that requires both elevated privileges and a dedicated user thread just to copy a block of structures from the kernel to the user." - Casey Muratori

boreal.aggydaggy.com

No. First, entities probably shouldn't be a pointer. std::vector is not a large data type, and so it should be on the stack (unless you have a really, really good reason for putting it on the heap). You've got a few syntax errors there since entities is a pointer, but you're treating it like it's not a pointer.

Second of all, entities doesn't hold pointers. It holds actual Entity objects (i.e. the full object, not a pointer to an Entity object). So you shouldn't be adding to with new Player(), nor should you have to use the -> operator, nor should you have to delete the elements in the vector.

You probably meant something more like this:

vector<Entity*> entities;
entities.push_back(new Player());

for (int i = 0; i < entities.size(); i++)
entities->update();

for (int i = 0; i < entities.size(); i++) // Note: calling delete entities doesn't change the size of entities
delete entities;


Note, however, that it is really, really, *really* discouraged to use raw pointers within a vector. If entities goes out of scope or gets its destructor called when an exception is thrown, the memory of the Entity objects is never freed, and you've got a memory leak. As SimonForsman said, using some kind of smart pointer is a much more preferred solution. If you were doing that, you could do something like this:


vector<std::shared_ptr<Entity>> entities; // std::shared_ptr or boost::shared_ptr, depending on if you're using C++11 or boost
entities.push_back(new Player());

for (int i = 0; i < entities.size(); i++)
entities->update();

// Look, no cleanup! It all gets handled automagically
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

In the context of a game, when would you want to use one over the other?

Not to answer your question, but because you mentioned "in the context of a game", I suggest you consider about cpu cache optimization (google if you are not familiar with it) in your memory management strategy.
cpu cache may influence how you manage your memory, and the performance of your game.

https://www.kbasm.com -- My personal website

https://github.com/wqking/eventpp  eventpp -- C++ library for event dispatcher and callback list

https://github.com/cpgf/cpgf  cpgf library -- free C++ open source library for reflection, serialization, script binding, callbacks, and meta data for OpenGL Box2D, SFML and Irrlicht.

This topic is closed to new replies.

Advertisement