Questions about encapsulation, resource management, global variables* and the like...

Started by
22 comments, last by rip-off 11 years, 3 months ago

You can (and probably should) store as many tiles as you like in a single texture and render them by index.

If you're using a resource caching strategy then that makes sense, though. Otherwise I usually prefer to load resources encapsulated as objects in the lowest context that they're needed in (which is usually near the top).

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
Advertisement
OK, let me ask this...

When is it acceptable to use global variables? In my case, I need certain variables across multiple classes. Encapsulation prevents this. Wouldn't this be a case where global variables would be needed? If the limitations of the acceptable method cause a hindrance, shouldn't the less acceptable method be allowed?

I've tried looking at some of the open source engines, like Ogre, but dear Lord! How anyone can continue development in that obfuscated tangled mess of code is beyond me! I cannot get anything out of it but how to obfuscate code.

[quote name='MarkS' timestamp='1356570181' post='5014560']
I need certain variables across multiple classes.
[/quote]

Why?

[quote name='MarkS' timestamp='1356570181' post='5014560']
Encapsulation prevents this.
[/quote]

Why?

C++: A Dialog | C++0x Features: Part1 (lambdas, auto, static_assert) , Part 2 (rvalue references) , Part 3 (decltype) | Write Games | Fix Your Timestep!

How does encapsulation prevent sharing?

A Bitmap class can be used to encapsulate a bitmap/texture resource and then you just load/create an instance and then hand it to the object that will be doing the rendering. When you're done with it you destroy the object to free the resource.

Also, most real-world codebases are measured using the scientific unit "wtfs-per-minute".

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
When is it acceptable to use global variables?

every time you can't come up with a better solution. So it is all up to the level of the programmer involved. For experienced and educated programmers, the answer is "never" or "never with some very rare exceptions (ie. logs)".. for programmers with less experience, education and time the answer changes accordingly.

Stefano Casillo
TWITTER: [twitter]KunosStefano[/twitter]
AssettoCorsa - netKar PRO - Kunos Simulazioni

Global variables can be fine, and it certainly helps when debugging to just be able to type gResourceMgr into a Watch window and get at the resource lists.

I think the resource loader is fine to be global - it's the sort of thing you would only want one of in a process. Every engine I've ever worked with has had the resource loader be global. I certainly wouldn't want to pass a pointer to it through every function that could possibly call a function that might call a function that needs to get a resource.

Global variables may be frowned upon, but you are allowed to use function parameters. In this case the render function needs a pointer to the mesh and a pointer to the tile_level or the resource objects. Is that so hard to arrange? It should also be easy to pass a pointer to the mesh without storing intermediates on tile_layer and sprite. Just call a function after the mesh is loaded.

It's perfectly fine to use globals in C++, though instead of accessing them directly you should access them via functions to provide some level of encapsulation. It's just good practice to minimize the number of globals to avoid your code becoming an unmanagable spaghetti mess. For resource management, I personally use globals since passing pointers to resource repositories everywhere where needed would be much worse option.

Cheers, Jarkko

I personally use globals since passing pointers to resource repositories everywhere where needed would be much worse option.

This view seems to be resurging around here at the moment. Some points...

If you are finding you need to pass a resource container around all over the place, there is something wrong with your design at a higher level. Making the container global state just masks this problem, it doesn't solve it. How many places should it be necessary to access a texture? A sound file? A script? What kind of extensible and robust design would require access to such things peppered all over the codebase?

One of the many problems with using global state is it makes it too easy to cut corners. I'm in the depths of my physics code and have an urge to play a sound when objects collide, or update a texture to show a hit mark. Easy to do and forget that I did later. But my physics code is now linked to my audio or rendering code in a way it needn't be. If the resources are not available, it forces me to stop and think of a less intertwined solution.

Nobody is suggesting the alternative to globals is to pass a pointer to some kind of state container into every function. This is a (real-world) anti-pattern that suffers from almost all of the issues that having global state can have in terms of design. The point is it is good to let the compiler and language enfore constraints about what can access what from where.

Robust and extensible code, we have learned over the years, is build from modular, black-boxed components that can be tested in isolation and interconnected in the minimal way required. Any design that moves away from this, whether it be global state, passing pointers around to a global container, singletons, whatever, is probably not going to lead to a maintainable design when projects grow out of triviality.

While I agree with your principle in general, there are practical scenarios where global access to resources is much more pragmatic solution. When you find the need to access a resource in the depths of the code, it can be very cumbersome to change all the interfaces & functions to pass the resource all way through the necessary callstack. You may even have some very generic functions in the callstack where it makes no sense to change the interface to pass specific resources through the interfaces.

If you have need to play sound in the depths of physics code, global access to sound resources doesn't endanger modularity any more than explicitly passing the resources. In both cases you need to #include sound code in your physics code, which should be enough of a red flag.

This topic is closed to new replies.

Advertisement