Jump to content
  • Advertisement
Sign in to follow this  
Danicco

Why are static variables bad?

This topic is 2138 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've read a few threads here that people advise against static variables, and the argument is usually because anything global is bad, but besides this, why are static variables considered bad?

 

Do they perform badly or something like that?

 

I'm asking because I've got my engine structure with modules, and I'm using static variables for each module so my base classes can access it.

 

class GameEngine
{
    public:
        GameEngine()
        {
            resourceModule = &_resourceModule;
        };
 
        static ResourceModule* resourceModule;
    private:
        ResourceModule _resourceModule;
};

 

#include "GameEngine.h"
 
void Image::Load(string imageName)
{
    //Texture2D* _texture;
    _texture = GameEngine::resourceModule->GetLoadedTexture(imageName);
}

 

Images are meant to be used like this:

 

void SomeGameFunction()
{
    Image* newImage = new Image();
    newImage->Load("imageNameHere");
}

 

I'm currently doing some encapsulation and blocking accesses to base classes that I don't want exposed, so other programmers don't ever access a "Texture2D" class for example, and when I looked to these static variables I thought they might be an issue but I couldn't find of any good solutions for it, that is, if they require a solution...

 

So I remembered the topics against static variables I thought I should ask, why are static variables considered bad?

Share this post


Link to post
Share on other sites
Advertisement

It's not that static variables are bad necessarily, but they are often misused and that can lead to code that is rather unpleasant to work with.

 

-Josh

Share this post


Link to post
Share on other sites

Right. Static variables are bad when used incorrectly. Making static variables globally accessible invites the programmer to access that variable at any point in the code without any clear indication from outside that code that there is a dependency on that global variable. This makes it impossible to test or reuse software components as individual units. Incorrectly used global static variables also threaten to wreak havoc all over your codebase whenever you attempt to change the way the variable is used or what it means. The alternative to using global static variables is usually to implement form of dependency injection so that any unit that depends on the variable will have its dependency clearly and explicitly indicated. Often this also has the benefit of compile-time error checking -- if you forget to pass that variable to your constructor or method that depends on it, then it won't compile.

 

Another potential drawback to using bare statics is that they are not thread safe. Any thread can access and modify the static without any sort of locking.

Share this post


Link to post
Share on other sites

Code tends to be more maintainable and have fewer ways to introduce bugs when there are fewer accessible variables from a given point of execution (of any kind, not just statics) and each variable is in the narrowest scope (local variables < ref arguments < closures <= instance members < thread-local storage < static members = global variables).  Static variables have the widest possible scope and longest lifetime.

 

Static variables can pose serious problems for:

- Decoupling.

- Code reuse.

- Thread safety.

- Restarting the game without relaunching the executable.

 

Statics can be perfectly fine as long as you always keep those things in mind.

Edited by Nypyren

Share this post


Link to post
Share on other sites
Essentially one of the more better know forms of improving your code is making it more modular, i.e. each section can exist without crashing even if another piece of code is not there that it requires to do anything interesting. That sort of "decomposition" of classes into little black boxes makes code simpler to track because it implies that each class can change it's members out or create multiple copies of objects without introducing bugs.

Static tends to go against that methodology because it implies there is only every one instantiation of a certain variable that is shared between everything. In a way it isn't necessarily a "global" but it sort of becomes this unnatural link of a permanent object that "belongs to everyone."

Usually something that belongs to everyone introduces things like bugs where state is changed across contexts or just complicates understanding which objects are accessing it.

Share this post


Link to post
Share on other sites

Your original example has conflated the use of static (or class) variables and public access to data.  The two topics are unrelated and orthogonal.

 

There's nothing at all wrong with using a class variable, where appropriate.

 

There are serious problems with using a publicly accessible variable of static storage duration, whether at namespace level or class level (these are known as 'global variables' in the C language and as a consequence colloquially also in the C++ language).

 

The biggest problem with the original example code is the unnecessary coupling between the GameEngine class and the Image class.  With that design, not only is the coupling brittle (ie. if i change the GameEngine, I have to change the Image) but the design prevents me from reusing the Image class in, say, a game editor or image editor that does not need a GameEngine.  Writing unit tests for your Image is next to impossible.  None of these problem have anything to do with the storage duration of your data but are a direct result of the accessibility of your data.

Share this post


Link to post
Share on other sites


I'm asking because I've got my engine structure with modules, and I'm using static variables for each module so my base classes can access it.

 

In addition to what the others have said, this is an inevitable bad design you are applying here. Having your modules globally accessible might seem tempting at first, but it will inevitably lead to a pile of cluttered spaghetti code. You might think "well, if I stop doing so I might end up having to pass my modules to everything and every constructor will have like 5 arguments just because of this", but this is not as it seems. You can end up in such a situation, but the main benefit from making your modules non-global are the you'll have to think about a clever design that will avoid you having to pass like the graphics-module 10 layers down into 100 different classes. This will force you to try to decouple your classes as much as possible, enforce proper encapsulation, etc, etc. In the end, you'll end up with much more usable classes, without hidden dependencies, and, I predict you, you'll actually save more work than you'd have if you made all those global.

 

And, since the others have already given a proper shot at the original question, and since I'm on it, here are some more hints regarding your overall design (only read on if you want some feedback over your original thought process):

 


GameEngine::resourceModule->GetLoadedTexture(imageName);

 

While I do not see the rest of the class, it appears the resourceModule has too much responsibility. I suppose it has methods for loading and creating textures, meshes, etc... and will do so on? That violates the single responsibility principle, and while this and other rules aren't necessary important for you to follow right now, its never too early to start using them. In short, you are better of splitting the different resource caches, and also split the loading functionality into its own class.

 


Image* newImage = new Image();

newImage->Load("imageNameHere");

 

Also, I'd rather split the loading-method from the image class. Such a design like here makes it hard to extend on things, if you have a seperate loader class its easier to add new loading methods, without breaking apart the other code.

 

Just some additional thoughts, if you ever feel the need to improve something or feel like your current design isn't working anymore as you'd expected...

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!