Advice on global variables

Started by
48 comments, last by Nathan Baum 17 years ago
Hi, Reading several threads and other resouorces, I keep hearing global variables are a bad thing. Is this correct ? and what is the best solution to avoid using globals? Here is a quick example from a project, I'm not looking for anyone to re-code this, just advice on better programming techniques.

// Window Enviroment Settings ----------------------------
HDC		hDC = NULL;		
HGLRC		hRC = NULL;		
HWND		hWnd = NULL;		
HINSTANCE       hInstance;		
DEVMODE		DMsaved;		

bool		keys[256];		
bool		active = TRUE;		

bool		fullscreen = FALSE;	
bool		scrVSync = FALSE;	
int		scrWidth = 1024;	
int		scrHeight = 768;	
int		scrBitDepth = 32;	

// Camera
CCamera		objCamera; 
float		CAMERA_FARPLANE = 50000;	
float		FOV = 52.0f;		

// Font & Text variables
GLuint		baseFont;
GLuint		baseBitmapFont;
GLuint		texBitmapFont;

// Textures
GLuint		texCrosshair;
GLuint		texHud;

// Mouse Variables
// Move & click
bool		MouseMove = FALSE;    
int		MouseButton = -1;	
//Mouse Position
GLfloat		MoveXcoord, MoveYcoord;		
int		clickXcoord, clickYcoord;

// timing Variables
int		FPSCount = 0;
char*		FPSCountTxt = "";
DWORD		timeCurrentTime = 0;
DWORD		timeDemoStartTime = 0;
DWORD		timeElapsedTime = 0;
char*		timeElapsedTxt = "";

// Testing Variables
bool		showHelp = FALSE;
bool		showWireframe = FALSE;
bool		showFog = FALSE;
bool		enableLighting = TRUE;
bool		enableSound = TRUE;
bool		enableFrustum = TRUE;




Already this is getting very large, and very messy, and this is still a simple project. Most of the examples I have been following are from NeHe, which I'm told some of his code is actually C, not C++ !! Although the 'code downloads' for the lessons are labelled as Visual C++ (sorry noobie alert) I'm still learning the difference. Besides the point anyway, but is there a better way to structure an application, and avoid so many globals ?? Thanks
It's not until we have fallen, we realize how much it hurts !
Advertisement
When people tell you something is bad or wrong (programming-wise), they usually mean that you shouldn't use it unless the alternative is worse. For instance, many sources will tell you that goto should never be used. However, there are times when it can be useful.

I would suggest trying to avoid using global variables as much as possible. There's very little security regarding when and how these variables can be altered. This can make debugging and maintenance much more difficult.

Personally, I would try to wrap some of the values up into a class or struct, just for the sake of readability and maintenance. All the screen stuff can go into a class. The camera, font and mouse variables can also be placed into their own classes. At program start up, just create instances of the necessary classes. This makes passing the values around to functions much easier. And, if you find you need to add another value, it can simply be added to the appropriate class, rather than needing to update the function and every where the function is called.
That kind of thing definitely gets ugly and doesn't scale (as far as maintainability goes at least). Since you're posting it as an example, you're already aware of that.

I think every time this question comes up, a huge debate on global variables versus singletons ensues. I don't have the time or patience to get into that argument because they are always argued about as if the opposing side thought the other was a silver bullet.

What I *will* say, however, is that at the absolute very least, instead of letting naked booleans and such sit out there, they should probably be grouped together in the way that makes most logical sense to you. Perhaps a "static config" (something that doesn't change, that is read once from a config file of sorts) and a "dynamic config" (user-changeable settings and the likes, which can change).

How you control access to them depends on the constraints you want to put on your software, so that's up to you.
Hey there,

I personally like to use 'smart' singletons, as desbribed below.
#include <memory>class MySettings{private:	const static std::auto_ptr<MySettings> m_staticInstance;	tbthSettings();public:	virtual ~MySettings();	static MySettings *getUniqueInstance(void) {		return m_staticInstance.get();	}};const std::auto_ptr<MySettings> MySettings::m_staticInstance(new MySettings()); // in cpp file...

IMO, they pretty much look like global variables, except that they have the advantages that classes have.
Cheers
StratBoy61
Global variables are a Bad Thing in that they are commonly used by programmers who don't know how to do proper OO design but who don't know that they aren't doing proper OO design. A similar thing is true of singletons: People usually use singletons because they don't know how to avoid global variables (because they don't know proper OO design) but they think that singletons "don't count" as global variables.

Quote:IMO, they pretty much look like global variables, except that they have the advantages that classes have.

You can have global variables with class type.
Quote:Original post by StratBoy61
Hey there,

I personally like to use 'smart' singletons, as desbribed below.
*** Source Snippet Removed ***
IMO, they pretty much look like global variables, except that they have the advantages that classes have.
Cheers
StratBoy61
Although this may work for you, I wouldn't be too quick to recommend the use of singletons as a solution to the global variable problem. There are many aspects of singleton usage that are less than obvious (not the least of which is order of construction and destruction).

@The OP: I would at least read this before deciding whether or not to make use of singletons in your own code.
The Law of Demeter states that you should only use objects which you've:
  • Created yourself, or
  • Received as an argument.


The objective (and result) of this law is to reduce coupling between your modules, which in turn results in modifications being more local (you don't have system-wide dependencies to follow).

Therefore, if an object or method expects to manipulate something, it should either create it itself or expect to receive it as an argument (or constructor argument). Otherwise, the object becomes too reliant on external structure, which make its testing, reuse and modification much harder, and also creates a direct dependency between the object and the used element.

Neither global variables nor singletons are valid with respect with the law (and, in fact, neither is better than the other anyway, because they are destined to solve different problems anyway).
eeerrr !!

OK so I'm going for a class or struct right ?

Now the question, which one ?

Structure, doesn't seem an improvement, other than, ... well .. it's structured !

Would be a bit more organized I guess:

typedef struct sWindow{  bool    fullscreen;		  int     scrWidth;		  int     scrHeight;		  int     scrBitDepth;	} myWindow;


example:
myWindow.fullscreen = TRUE;
myWindow.scrWidth= 1024;
etc etc

if anything this is more code no ??
having to put "myWindow." before everything
It's not until we have fallen, we realize how much it hurts !
1.) That's a C idiom for creating structs. In C++, you don't need the typedef:

// C idiom - works but can be considered deprecatedtypedef struct point_{    int x;    int y;} point;// C++ idiomstruct point{    int x;    int y;};


2.) I think you've missed the point. Avoiding global variables does not mean wrapping them in a struct(!) - rather, it involves designing your program in such a manner as they aren't needed. Pass them as arguments - use classes to encapsulate other objects which are tightly related to ('part of') themselves. A highly simplified example:

// Bad#include <iostream>int x;void tripleX(){    x *= 3;}int main(){    x = 3;    doubleX();    std::cout << x;}// Good#include <iostream>int triple(int input){    /* Double is no longer tied to one variable - any int can be passed to it.       Also, we better abstract the concept of doubling a number - with the       result that the code is easier to reuse. */    return input *= 3;}int main(){    int x = 3;    std::cout << double(x);    /* Also, a return value saves us a line of code in this example. Although,       this is of course also a case of design - it might sometimes not be       what we want! */}


EDIT: D'oh.
EDIT 1306BST 25/03/07: Missed a semicolon

[Edited by - TheUnbeliever on March 25, 2007 6:27:55 AM]
[TheUnbeliever]
ok, I get what your saying.

Maybe I am doing something more dramatically wrong here.

just an example of various function I'm using:

CreateGLWindow(WND_TITLE, scrWidth, scrHeight) // in main

glOrtho(0, scrWidth, 0, scrHeight, -1, 1); // various times (fonts, hud, crosshair)

Draw_loadingScreen(scrWidth, scrHeight); // in render

Draw_creditsScreen(scrWidth, scrHeight); // in render

That's just an example of 2 variables (scrWidth, scrHeight)
I could list a dozen more, for mouse and key presses

Surely these need to be globals right ?
It's not until we have fallen, we realize how much it hurts !

This topic is closed to new replies.

Advertisement