Sign in to follow this  
finky45

c++ question about stack , heap and dereferencing

Recommended Posts

This is probably a stupid question as I think I know what the answer is but I want to make sure: By declaring an object with the "new" operator, which creates something on the heap, does that mean that all variables AND pointers contained in it are also on the heap? If so... another question: In my game right now, I have a lot of pointer dereferencing this->getThat()->getSomething()->getAnother()->youguessedit(); No, that is not an exaggeration. Is this really slow? And if it is, do I gain any speed by not creating pointers in objects that I know will be created on the heap anyway? So I would end up using: this->that().something().another().youguessedit(); ...Or is it the same thing?

Share this post


Link to post
Share on other sites
Quote:

By declaring an object with the "new" operator, which creates something on the heap, does that mean that all variables AND pointers contained in it are also on the heap?

More or less, yes. There are nitpicky little details and the occasionally obscure edge case, but generally once you put something on the heap, it and its subobjects are on the heap.

Quote:

Is this really slow? And if it is, do I gain any speed by not creating pointers in objects that I know will be created on the heap anyway? So I would end up using:
this->that().something().another().youguessedit();

...Or is it the same thing?

There are number of things wrong with this technique. Speed is one of them -- or rather, decreases in technical speed are a side-effect of the poor cache locality of the objects you are likely accessing. That is to say, all those pointers you're following may be pointing to all sorts of different locations in memory, and jumping around like that isn't particularly optimal.

However, the speed penality is probaby small -- small enough that, if this were a good, correct way to access your objects, it would not be worth changing.

However, it's not a good way to access your objects. You aren't doing any checks for null pointers, for example. If the objects can't ever be null, you should perhaps be returning references instead.

How you expose the properties (return them) is not neccessarily the same as how you store them (you could store pointers to Foo inside the class, but return a reference to Foo from GetFoo()). Expose them according to how they should be used -- generally references if they cannot be null -- and store them according to how they should exist. If a particular field of an objects is always present, there's usually no reason for that field to be a pointer to heap storage.

In general, it's usually better to avoid pointers unless you need the behavior a pointer can provide you.

A final note is that this kind of deep pointer chasing is usually symptomatic of poor design: it suggests that you are doing a lot of a processing related to the tail-end of the pointer chain at a higher level point (the base-end of the pointer chain) and thus that your objects are probably little more than "dumb" containers for data with a bunch of naive get/set methods.

Share this post


Link to post
Share on other sites
when you create an object on the heap the whole object is on the heap, so yes to the first question. Each pointer dereference is a memory access and as such is a performance hit but slow no not really. not using pointers means those functions could be inlined. The main question I would be asking myself though is why is it necessary to hop through three or four references to reach something. It sounds like you may have over-engineered and now have containers of containers of containers.

Share this post


Link to post
Share on other sites
Quote:
Original post by jpetrie

However, it's not a good way to access your objects. You aren't doing any checks for null pointers, for example. If the objects can't ever be null, you should perhaps be returning references instead.


Well most of them can be null, when they are deleted.

Quote:
Original post by jpetrie
In general, it's usually better to avoid pointers unless you need the behavior a pointer can provide you.


The reason I did this was to make damn sure my objects would be stored on the heap as I would have lots of them and didn't want to run out of stack memory.

Quote:
Original post by jpetrie
A final note is that this kind of deep pointer chasing is usually symptomatic of poor design: it suggests that you are doing a lot of a processing related to the tail-end of the pointer chain at a higher level point (the base-end of the pointer chain) and thus that your objects are probably little more than "dumb" containers for data with a bunch of naive get/set methods.


Some are. I have an object which stores arrays of ships, bullets, asteroids etc... This is so I can do collision detection among my ships, and render lists of objects. Then each ship stores SDL_Surfaces (basically images) along with smaller objects such as guns, which also store SDL_Surfaces, about 32 each (SDL can't rotate images, I have to preload them).

My objects do more than just hold data:
When I call .Move() on my Ships, they will also set the angle and location (in the world) of their guns. That location is used by the render function to display things relative to each other on my screen.

But even if they were just dumb containers... isn't that what OOP is all about? organizing things in containers?

Another question about speed: Since my objects contain a lot of data that might be useless in some functions, for example, collision detection. I do plan on doing pixel-perfect detection at some point which means I will need the surfaces, but does making a call on a huge object take longer?

i.e "Object A has 1000 other objects (or pointers to them, if its the same thing for this purpose). Object B has only 5 other objects. If I make a call like ObjectA.getX vs. ObjectB.getX (where X is considerably smaller than the other members) will there be a difference? If so, how big, and why is there a difference? In other words when I make a call on an object does the whole object get copied somewhere, or only the part of it that I am trying to access?

Share this post


Link to post
Share on other sites
Quote:

The reason I did this was to make damn sure my objects would be stored on the heap as I would have lots of them and didn't want to run out of stack memory.

This is a premature optimization. It's surprisingly difficult to store too much information on the stack "accidentally." You don't need to make everything a pointer to ensure that, either, and you shouldn't. Remember that which region of memory an object ends up living in isn't as system as "pointer == heap, no pointer == stack." It also has to do with the location of the containg object and that object's declaration and initialization.

Quote:

Some are. I have an object which stores arrays of ships, bullets, asteroids etc... This is so I can do collision detection among my ships, and render lists of objects. Then each ship stores SDL_Surfaces (basically images) along with smaller objects such as guns, which also store SDL_Surfaces, about 32 each (SDL can't rotate images, I have to preload them).

There should be a separation between logic and presentation; if Ship contains any sort of game logic (a measure of life left, how much bullets the ship has, what weapons its carrying, how to fire the gun, et cetera) it is a logic object and should not have anything to do with rendering. Logic should drive rendering -- that is, tell the rendering subsystem what to draw based on current state -- but they should not, ideally, be mixed together.

Quote:

But even if they were just dumb containers... isn't that what OOP is all about? organizing things in containers?

Not at all. Object oriented design is about building complete representations that model reality in some way -- "objects" with understanding of both state and behavior. When you externalize your behavior, you start moving to the realm of procedural programming.

Furthermore, good OO design has a lot to do with isolating responsibily, scoping that responsibility to the smallest scope that makes sense. In your case, you seem to have an exeedingly large amount of responsibility tucked away at the high-level end of your objects, and almost no functionality at the low end. This gives the higher-level objects more responsiblity, violating the principle of single responsibility that helps make OO designs cleaner, more maintainable, and reusable.

Quote:

Another question about speed: Since my objects contain a lot of data that might be useless in some functions, for example, collision detection. I do plan on doing pixel-perfect detection at some point which means I will need the surfaces, but does making a call on a huge object take longer?

No, a member function call is, internally, usually just a call to a regular function that takes the first parameter ("this") that is a pointer to the object that function is being invoked on. The size of that object is irrelevant.

Share this post


Link to post
Share on other sites
Quote:
Original post by finky45
The reason I did this was to make damn sure my objects would be stored on the heap as I would have lots of them and didn't want to run out of stack memory.


This is generally faulty thinking. Consider, for example:


class Foo {
Bar x, y, z;
};


If we put a Foo on the heap, then its contained Bars are also all on the heap, because they are, well, contained. Baked right into the memory structure of the Foo object.

Quote:
My objects do more than just hold data:
When I call .Move() on my Ships, they will also set the angle and location (in the world) of their guns.


Good.

Quote:
That location is used by the render function to display things relative to each other on my screen.


This depends on how you do it, though. A very powerful guiding principle for OO is "tell, don't ask", aka dependency inversion.

Quote:
But even if they were just dumb containers... isn't that what OOP is all about? organizing things in containers?


OO is about breathing life into the "things". Organization is just good practice.

Quote:
i.e "Object A has 1000 other objects (or pointers to them, if its the same thing for this purpose). Object B has only 5 other objects. If I make a call like ObjectA.getX vs. ObjectB.getX (where X is considerably smaller than the other members) will there be a difference? If so, how big, and why is there a difference? In other words when I make a call on an object does the whole object get copied somewhere, or only the part of it that I am trying to access?


There is no such thing as partially copying an object. However, calling a function on an object does not involve copying it. Assuming getX() just returns an 'x' member of the object, what conceptually happens is that some known offset is added to the memory location of the object, and a type-of-x-sized chunk of memory is retrieved from that location.




Let's try an example.


// Suppose we have some declarations like (of course I am omitting lots of stuff)
class Renderer {
SDL_Surface* screen;
public:
// Draw the region (x, y, w, h) of the surface onto screen, at (xpos, ypos).
void drawSpriteAt(int xpos, int ypos, int x, int y, int w, int h, const SDL_Surface* surface) const;
};

class Level {
std::vector<Enemy*> enemies;

public:
Enemy* getEnemy(int index) const;
};

class Enemy {
SDL_Surface* surface;
SDL_Rect rect; // the portion of the surface that illustrates this enemy
SDL_Point position;

public:
SDL_Surface* getSurface() const;
SDL_Rect& getRect() const;
SDL_Point& getPosition() const;
};

Level* level;
Renderer* renderer;

// bad in many ways
renderer->drawSpriteAt(level->getEnemy(i)->getPosition().x, level->getEnemy(i)->getPosition().y, level->getEnemy(i)->getRect().x, level->getEnemy(i)->getRect().y, level->getEnemy(i)->getRect().w, level->getEnemy(i)->getRect().h, level->getEnemy(i)->getSurface());



On the surface, it seems like we're doing a few things correctly: we have accessors instead of just looking at data members directly, and the code has been written to be const-correct. However, we're actually making things hugely more complicated than they need to be, and exactly wrongly organized.

The first things we can do are to get rid of the unnecessary indirection (keep in mind that even if we put all *our* stuff on the stack, the really *big* stuff - i.e., the data pointed at by the SDL_Surface*s - will be put on the heap by SDL), and use a reference to clean up the repeated access pattern.


class Renderer {
SDL_Surface* screen;
public:
// Draw the region (x, y, w, h) of the surface onto screen, at (xpos, ypos).
void drawSpriteAt(int xpos, int ypos, int x, int y, int w, int h, const SDL_Surface* surface) const;
};

class Level {
std::vector<Enemy> enemies;

public:
Enemy& getEnemy(int index) const;
};

class Enemy {
SDL_Surface* surface;
SDL_Rect rect;
SDL_Point position;

public:
SDL_Surface* getSurface() const;
SDL_Rect& getRect() const;
SDL_Point& getPosition() const;
};

Level level;
Renderer renderer;

// Improved slightly
Enemy& e = level.getEnemy(i);
SDL_Point& point = e.getPosition();
SDL_Rect& rect = e.getRect();

renderer->drawSpriteAt(point.x, point.y, rect.x, rect.y, rect.w, rect.h, e.getSurface());



Now the function call is a lot more readable: we can immediately see what each parameter is for. But it's still rather complicated: why not just pass the structures for position and sprite-rect, and let drawSpriteAt do the unpacking? (I could have made the first example worse: imagine separate accessor functions for x, y, w, h of the rect for example!)

But that is still missing the point: we are reaching into the Enemy structure to do the job of drawing it. That puts the responsibility in the wrong place. The Enemy is the object with the information that's needed for drawing, so the Enemy should assume the responsibility for that draw call. We apply that tell, don't ask principle, and give the Enemy the power to draw itself, and remove the now-unneeded accessors.


class Renderer {
SDL_Surface* screen;
public:
// Draw the region rect of the surface onto screen, at p.
void drawSpriteAt(SDL_Point p, SDL_Rect rect, const SDL_Surface* surface) const;
};

class Level {
std::vector<Enemy> enemies;

public:
Enemy& getEnemy(int index) const;
int enemyCount() const;
};

class Enemy {
SDL_Surface* surface;
SDL_Rect rect;
SDL_Point position;

public:
// This time, I'll show the implementation:
void drawTo(const Renderer& r) {
r.drawSpriteAt(position, rect, surface);
}
};

Level level;
Renderer renderer;

// Improving bit by bit... now let's see the whole loop:
for (int i = 0; i < level.enemyCount(); ++i) {
level.getEnemy(i).drawTo(renderer);
}



Wow, much shorter this time! But we can still improve, by repeating the technique for the Level. It knows what all the enemies are; why ask it continually for each enemy in order to draw them? The same principle applies: the level can do the drawing.



class Renderer {
SDL_Surface* screen;
public:
// Draw the region rect of the surface onto screen, at p.
void drawSpriteAt(SDL_Point p, SDL_Rect rect, const SDL_Surface* surface) const;
};

class Level {
std::vector<Enemy> enemies;

public:
void drawAllEnemies(const Renderer& r) const {
// Because we're not "squeezed through the interface" of another class now,
// we can do the loop in a more natural way:
std::vector<Enemy> end = enemies.end();
for (std::vector<Enemy> it = enemies.begin(); it != end; ++it) {
it->drawTo(r);
}
}
};

class Enemy {
SDL_Surface* surface;
SDL_Rect rect;
SDL_Point position;

public:
// This time, I'll show the implementation:
void drawTo(const Renderer& r) {
r.drawSpriteAt(position, rect, surface);
}
};

Level level;
Renderer renderer;

level.drawAllEnemies(renderer);



Beautiful. Now all the code is in the right place. Only one more change I want to make: the Enemy class presumably has a lot of other stuff in it besides the data for drawing the critter, and there are presumably lots of other things in the game that will need to be drawn the same way. We don't want to have to duplicate this setup in other classes, so it makes sense to extract a Sprite struct, and give the drawTo() function to that. Then the Enemy simply holds a Sprite, and delegates to it for drawing:


class Enemy {
Sprite s; // looks very much like the old Enemy above :)
public:
void drawTo(const Renderer& r) {
s.drawTo(r);
}
};


Now we can reuse that in other classes. Instead of duplicating the set of data members and the drawTo implementation, we just duplicate this bit of delegation (and we don't even need that, if we make clever use of inheritance; but be careful - composition and delegation is often more flexible and avoids subtle design problems).

Share this post


Link to post
Share on other sites
Wow Zahlman, that's like a whole mini-tutorial ^^. I've always been a little confused about a nice way to keep code organized, readable and "OOP". Your examples made it pretty clear to me and seem like a nice guideline (so I bookmarked this thread). Thank you ^^!

Sorry if this is seen as an annoying off-topic post.. But I just wanted to mention it.

Share this post


Link to post
Share on other sites
Got another question for Zahlman:

In my game, the player will always be in the middle of the screen. Consequently where I draw the enemies depends on where the player is in the level.

I don't know how I can implement this while keeping my code object oriented.

If I tell the enemy to draw itself, it needs to know where the player is, to give the right SDL_Rect to the renderer. But it knowing where the player is, is out of its scope. I don't think the enemies need to know where the player is located for drawing purposes. However they will probably know where the player is for other purposes (such as AI), which confuses me even more...

Also, It doesn't seem right for it to be in the renderer object since that brings me back to the kind of code I had before, with getPlayer() type methods.

So, where is the calculation made to offset the SDL_Rect that will be given to the renderer? Where would you put it?

Share this post


Link to post
Share on other sites
Quote:
Original post by finky45
If I tell the enemy to draw itself, it needs to know where the player is, to give the right SDL_Rect to the renderer. But it knowing where the player is, is out of its scope.


Quote:
So, where is the calculation made to offset the SDL_Rect that will be given to the renderer? Where would you put it?


No. The renderer knows where it is. The calculation is made in the renderer. The enemy (and player!) gives the renderer an SDL_Point that represents its position in "world space". (The SDL_Rect in my example is for finding a *part* of the spritesheet image to blit *from*, onto the screen.) The renderer translates that point accordingly. The renderer happens to be always on top of the player, because we tell the player about the existence of the renderer at creation (and it stores some kind of reference or pointer), and when the player moves, it tells the renderer to move also.

If the idea of a renderer "being somewhere" bothers you, think of it as a camera instead. Or you may need to make a separate "camera" object that is a part of the renderer (similar to how the "sprite" gets extracted from the enemy).

Quote:
I don't think the enemies need to know where the player is located for drawing purposes. However they will probably know where the player is for other purposes (such as AI), which confuses me even more...


The enemy asks the player "how far are you from here?", giving its own location. For normal games ( ;) ) the enemy is not going to care about the player's position relative to the edges of the world, but only relative to itself.



Share this post


Link to post
Share on other sites
Sorry if this has been covered in the above posts (I only read the first couple), but even if you want the internal representation of something to be a pointer so that you can allocate it on the heap, you can always dereference the pointer inside the class that contains it and return it as a reference.

Generally, any time you dereference a pointer by using * or -> it's a good practice to check to see if it's NULL first. Doing that in the containing class (when you return the reference), and asserting in the case where something is NULL when it shouldn't be can clean up your code a bit, and not having to debug crashes in lines of code that look like the following (or worse) is always a plus:

mObjects[i]->GetObject()->Something()->OrOther()->Ridiculousness()->Mwahaha()->Dead();

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman

The Enemy is the object with the information that's needed for drawing, so the Enemy should assume the responsibility for that draw call. We apply that tell, don't ask principle, and give the Enemy the power to draw itself, and remove the now-unneeded accessors.


What about using a drawVisitor to handle all the functionality of drawing? Remove the power of the Enemy to draw itself, but give the Enemy the ability to provide any necessary information that is required by the drawVisitor, or any other visitor.

Wouldn't this allow for any kind of rendering Visitor to be applied? You could render your Enemies in 2-D or 3-D, or even use pure text output.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Quote:
Original post by finky45
If I tell the enemy to draw itself, it needs to know where the player is, to give the right SDL_Rect to the renderer. But it knowing where the player is, is out of its scope.


Quote:
So, where is the calculation made to offset the SDL_Rect that will be given to the renderer? Where would you put it?


No. The renderer knows where it is. The calculation is made in the renderer. The enemy (and player!) gives the renderer an SDL_Point that represents its position in "world space". (The SDL_Rect in my example is for finding a *part* of the spritesheet image to blit *from*, onto the screen.) The renderer translates that point accordingly. The renderer happens to be always on top of the player, because we tell the player about the existence of the renderer at creation (and it stores some kind of reference or pointer), and when the player moves, it tells the renderer to move also.

If the idea of a renderer "being somewhere" bothers you, think of it as a camera instead. Or you may need to make a separate "camera" object that is a part of the renderer (similar to how the "sprite" gets extracted from the enemy).

Quote:
I don't think the enemies need to know where the player is located for drawing purposes. However they will probably know where the player is for other purposes (such as AI), which confuses me even more...


The enemy asks the player "how far are you from here?", giving its own location. For normal games ( ;) ) the enemy is not going to care about the player's position relative to the edges of the world, but only relative to itself.


You're a smart fella Zhalman. Your responses give me so many wonderful ideas and open up the possibilities of my code. Having a "camera" class lets me easily draw 2 different level locations on the screen. If I ever end up finishing this game I think your name belongs in the credits =), as well as other people on here. Hopefully I won't be needing your help again, but I most likely will.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shakedown
Quote:
Original post by Zahlman

The Enemy is the object with the information that's needed for drawing, so the Enemy should assume the responsibility for that draw call. We apply that tell, don't ask principle, and give the Enemy the power to draw itself, and remove the now-unneeded accessors.


What about using a drawVisitor to handle all the functionality of drawing? Remove the power of the Enemy to draw itself, but give the Enemy the ability to provide any necessary information that is required by the drawVisitor, or any other visitor.

Wouldn't this allow for any kind of rendering Visitor to be applied? You could render your Enemies in 2-D or 3-D, or even use pure text output.


Sure. I was trying not to cover too much at once. [wink] Programming is naturally an iterative process, though; we add extra layers of flexibility as a need is proven, and continually make minor improvements to the organization as we go (refactoring), to make those larger changes easier. Applying the Visitor pattern can be a refactoring - after we've already found that we need to draw in two different ways.

In a way, the Sprite factoring is a step in that direction, anyway. Right now, the Level is doing the "visiting", and the Enemies give back Sprite objects - except that actually, it delegates work to the Sprite objects instead. If we gave back data (in the form of "dumb" Sprites), the Visitor could decide how to do the drawing, but it comes at the expense of treating our Sprite like "just data". This is fine, pragmatically; it's better not to delude ourselves in cases like that. But first, establish a need.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this