Sign in to follow this  
NUCLEAR RABBIT

Is This A Bad Habit?

Recommended Posts

NUCLEAR RABBIT    318
Hello, I was wondering if using global variables (C++) is a bad habit to get into? Eample:
//Global Variable
int o;

void diaper()
{
    std::cout << "My Fav Number is 731";
    std::cout << "I LOve Peanut Butter!";
}

void poop()
{
   std::cout << "Whats Your fav Number? ";
     std::cin >> o;
}


If it is a bad habit, or there is a better way of keeping variables so i can use them Anywhere in my functions/program, How can i do this? -- Thanks.

Share this post


Link to post
Share on other sites
King of Men    394
Well... Let me be the contrarian voice and point out that there is such a thing as a pointer that really does need to be seen by the whole program, and even have its state changed occasionally. It also depends a bit on what you are doing. If you are working on, say, a snippet to analyse some data and make a few histograms, then globals are fine, because the effort of making properly encapsulated code is greater than the effort of maintaining a small non-encapsulated program. Particularly one that will only be needed for a few weeks anyway. Let me re-emphasise that 'small'; more than a thousand lines of code, and you definitely want encapsulation.

So, with the small caveats above, yes, globals are a bad habit for games programming. Don't use them for anything bigger than Tetris, at least not as a general thing.

Share this post


Link to post
Share on other sites
Fruny    1658
It's not a good habit, but it's not as bad as some people make it. Using singletons to pretend that you're not using globals is a significantly worse disease.

Share this post


Link to post
Share on other sites
tstrimp    1798
Quote:
Original post by King of Men
So, with the small caveats above, yes, globals are a bad habit for games programming. Don't use them for anything bigger than Tetris Pong, at least not as a general thing.


Share this post


Link to post
Share on other sites
games2live    122
Basicly, try to keep your variables as local as possible. That way, you wouldnt have to worry about different variables with the same name. For example, if you were making an FPS, you should have your player speed variable, and your bullet speed variable. Now, big projects can be confusing, and you might have the variable name "speed" for both. That could be a disaster! Either you would go super fast, or your bullet would go super slow. But by keeping your variables local, you can use Player.Speed, and Bullet.Speed. Alot better, isn't it?

Hope I helped,
Martin

Share this post


Link to post
Share on other sites
Benjamin Heath    925
When using global variables, it can be hard for yourself or another programmer to look at your code and find out where some given global variable is being significantly changed at some given time, simply because it's available to all of them. The difficulty lies in tracking just where the variable is declared, initialized, and all the places in which it's used. (Sound easy? Have a look at the Quake source code.) Throw in some multithreading, and you can have a lovely spaghetti dinner.

You just wish the guy who wrote it (perhaps you?) had simply kept the code clean and organized from the start in the first place, and had not been so lazy as to shove all these variables into the global namespace.

Keep it simple, but be smart about it.

Share this post


Link to post
Share on other sites
Boder    938
It's one of those dangerous but efficient things, like statically allocated arrays that you hope don't overflow.

Whenever I look at C source code to a program I get the uncontrollable urge to try and crash the program with buffer overflows.

Share this post


Link to post
Share on other sites
Sneftel    1788
Quote:
Original post by Boder
It's one of those dangerous but efficient things, like statically allocated arrays that you hope don't overflow.

Globals actually aren't necessarily more efficient than better-written equivalent code. In particular, having lots of globals can significantly increase the number of page faults.

Share this post


Link to post
Share on other sites
hh10k    589
Another reason not to use globals is that you have no idea which order they will be constructed and destructed. Singletons help ensure something is constructed when you want to use it, but things can get quite messy when you have several cross referenced objects that might be destructed in any order on exit. I got lazy once and I suffered for it :)

Share this post


Link to post
Share on other sites
Samurai Jack    455
What I stil do not understand about global wariables is what about devies? For some reason, sometimes you do not want to pass arguments all over the program. Take OpenGL for example. Once the device is created, you do not have to pass the device handle all the time you would like to something with graphics.

for example:

glVertex3i(1,1,1);

does not have to be like this:

void main()
{
COpenGLDevice* pDevice = new COpenGLDevice();
pDevice->glVertex3i(1,1,1);


What about a lib, and a global variable? Intel compiler complains you can only use external defined global variables, for example if you have a global variable in driver.cpp you should expose it in driver.h. What about if I would like to encapsulate but the user shod not need to access it directly?

One solution could be a Singleton, but with singletons it is hard to track memory leaks. If they are createded as static, they will be terminated at the end of the program, so you don't have full controll. If created dynamic, one might forget and you can not have a clean up procedure in a library.

In Quake 3 there were a lot of global variables and I believe it is common for many commerical products. There has to be an elegant soulution, that is not a singleton that can store internal global variables for libraries also.

What is more elegant?

a) glVertex3i(1,1,1);
b) pDevice->glVertex3i(1,1,1); //and all new and delete stuff
c) glVertex3i(pDevice,1,1,1); //urg?

Share this post


Link to post
Share on other sites
Benjamin Heath    925
Quote:
Original post by Samurai Jack
What I stil do not understand about global wariables is what about devies? For some reason, sometimes you do not want to pass arguments all over the program. Take OpenGL for example. Once the device is created, you do not have to pass the device handle all the time you would like to something with graphics.

for example:

glVertex3i(1,1,1);

does not have to be like this:

void main()
{
COpenGLDevice* pDevice = new COpenGLDevice();
pDevice->glVertex3i(1,1,1);
I'm not clear on what you mean. What's wrong, exactly, with the second sample? Your device is initialized inside an object, and so you'll have it for only as long as you need it.

Quote:
What about a lib, and a global variable? Intel compiler complains you can only use external defined global variables, for example if you have a global variable in driver.cpp you should expose it in driver.h. What about if I would like to encapsulate but the user shod not need to access it directly?
(It seems like you're misusing the conjunction 'but' there. I'm not sure.) If you'd like to encapsulate, and if you'd like to hide this variable, do so. What's the problem?

Quote:
One solution could be a Singleton, but with singletons it is hard to track memory leaks. If they are createded as static, they will be terminated at the end of the program, so you don't have full controll. If created dynamic, one might forget and you can not have a clean up procedure in a library.
I stay away from singletons. If the end programmer "forgets" to deallocate the memory he's allocated in an environment that requires this (such as C++), that's his problem, not mine. It's not hard.

Quote:
In Quake 3 there were a lot of global variables and I believe it is common for many commerical products. There has to be an elegant soulution, that is not a singleton that can store internal global variables for libraries also.

What is more elegant?

a) glVertex3i(1,1,1);
b) pDevice->glVertex3i(1,1,1); //and all new and delete stuff
c) glVertex3i(pDevice,1,1,1); //urg?
Device.glVertex3i(1, 1, 1); // how's that?

Share this post


Link to post
Share on other sites
Sneftel    1788
Quote:
Original post by Samurai Jack
What I stil do not understand about global wariables is what about devies? For some reason, sometimes you do not want to pass arguments all over the program. Take OpenGL for example. Once the device is created, you do not have to pass the device handle all the time you would like to something with graphics.

Scattering drawing calls over your entire program (the only situation where you have to pass the device handle around "all the time") is a bad idea for the same reason overuse of globals is a bad idea: Because it undercuts locality and makes it difficult to pinpoint problems.

Share this post


Link to post
Share on other sites
ZMaster    240
Using global variables isn't such a bad thing and using singletons isn't either. Singletons have various architectural advantages such as "initialize on first use". However, I would never declare global variables with C++ in the way you have done it in your example. You should definitely make use of namespaces and/or static members (+ the advantages of encapsulation) because they make your code way more readable and avoid problems when it comes to re-definitions/declarations with 3rd party libraries and such.
If this is more/equal performant compared to globals as shown in your example is another question. But generally you would prefer code readability over minimal performance increases, especially when there are a dozen things that are more obvious and easier to optimize in your code.

Share this post


Link to post
Share on other sites
_goat    804
Quote:
Original post by Sneftel
Quote:
Original post by Samurai Jack
What I stil do not understand about global wariables is what about devies? For some reason, sometimes you do not want to pass arguments all over the program. Take OpenGL for example. Once the device is created, you do not have to pass the device handle all the time you would like to something with graphics.

Scattering drawing calls over your entire program (the only situation where you have to pass the device handle around "all the time") is a bad idea for the same reason overuse of globals is a bad idea: Because it undercuts locality and makes it difficult to pinpoint problems.


God yes, I can only imagine how much time I've saved by having a single rendering function that asks all the models for their meshes, and in turn asks all the meshes for the required things (vertex buffers/index buffers, etc), rather than letting each type of object render itself internally.

Share this post


Link to post
Share on other sites
JY    289
Quote:
God yes, I can only imagine how much time I've saved by having a single rendering function that asks all the models for their meshes, and in turn asks all the meshes for the required things (vertex buffers/index buffers, etc), rather than letting each type of object render itself internally.


That's quite an interesting point. Aren't you moving away from the ethos of OO programming by doing it this way? Shouldn't each object be responsible for its own drawing?

Suppose you have an object that needs to be drawn but doesn't have a mesh per se. The rendering code then needs to ask the object what kind of drawing mechanism to use, then ask the object for its mesh (if it's a mesh object) or its other information (if its a different kind of object). This then requires the renderer to know about all the different possibilities of object types.

Whereas, if you let each object render itself the renderer simply calls the "render" method and that's it.

I'm currently constructing a 3D rendering platform so i'd be interested to know people's thoughts.

Share this post


Link to post
Share on other sites
superpig    1825
Quote:
Original post by _goat
Quote:
Original post by Sneftel
Quote:
Original post by Samurai Jack
What I stil do not understand about global wariables is what about devies? For some reason, sometimes you do not want to pass arguments all over the program. Take OpenGL for example. Once the device is created, you do not have to pass the device handle all the time you would like to something with graphics.

Scattering drawing calls over your entire program (the only situation where you have to pass the device handle around "all the time") is a bad idea for the same reason overuse of globals is a bad idea: Because it undercuts locality and makes it difficult to pinpoint problems.


God yes, I can only imagine how much time I've saved by having a single rendering function that asks all the models for their meshes, and in turn asks all the meshes for the required things (vertex buffers/index buffers, etc), rather than letting each type of object render itself internally.


Is that sarcasm? Because your second approach would be very poor OO design.

Don't make a single object responsible for very different tasks (e.g. both updating and rendering), because by putting them both in the same package you're coupling them together. What if you want to take your usual CEnemySoldier but have him star in a cutscene, requiring very different logic to drive him? You can't do that without either copy-pasting the code from object to object, or somehow using a CEnemySoldier for rendering while keeping the rest of him as 'dead weight.'

The correct approach would be to split out the rendering code from the update code into a seperate object - for example, CSkinnedCharacter - and give the main object a pointer to it, if necessary. Then you could have your CEnemySoldier and CCutsceneSoldier both holding a pointer to CSkinnedCharacter, ensuring they'll both render in exactly the same way (and hey, you might as well use it for CScientist and CRebel as well, they're skinned characters too), and you've got all the rendering code for a skinned character contained in CSkinnedCharacter, so if there are any problems with character rendering you know exactly where to look.

Whether you then call CSkinnedCharacter::Render() via CEnemySolder::Render() is pretty much irrelevant, though in a high-performance engine you'd gather all the actual rendering objects together and sort them by material or something first.

Share this post


Link to post
Share on other sites
ZMaster    240
@superpig: But wouldn't it be even better OO design to have CEnemySoldier and CCutsceneSolider derive from CSkinnedCharacter which implements a rendering routine for itself. Let's say via a virtual protected function which can be accessed by both CCutsceneSoldier and CEnemySoldier to render themselves and which could be overridden for any other CSkinnedCharacter which wants to implement it's own rendering function though?
I'm not sure about this... just asking.

Share this post


Link to post
Share on other sites
Spoonbender    1258
Quote:
Original post by Boder
It's one of those dangerous but efficient things, like statically allocated arrays that you hope don't overflow.


Globals aren't efficient. Like Sneftel said above, you can get more page faults. And it's much harder for the compiler to optimize, since the global has, well, global scope. It might be accessed from anywhere at any time. So keeping it in a register rather than in memory isn't really an option.

Quote:
It's not a good habit, but it's not as bad as some people make it. Using singletons to pretend that you're not using globals is a significantly worse disease.

Curious what you mean. Are you saying that you prefer globals over singletons themselves, or just that you prefer them over the "It's not a global, it's a singleton, and so it's perfectly fine, and good OO and not global at all"-mindset? [wink]

Share this post


Link to post
Share on other sites
superpig    1825
Quote:
Original post by ZMaster
@superpig: But wouldn't it be even better OO design to have CEnemySoldier and CCutsceneSolider derive from CSkinnedCharacter which implements a rendering routine for itself. Let's say via a virtual protected function which can be accessed by both CCutsceneSoldier and CEnemySoldier to render themselves and which could be overridden for any other CSkinnedCharacter which wants to implement it's own rendering function though?
I'm not sure about this... just asking.


Remember that by inheriting from a class, you don't just inherit its functions and fields; you also inherit the references to it (because your derived class could be type-cast to the base class). By inheriting CEnemySoldier from CSkinnedCharacter, CEnemySoldier could now be messed with both by code that refers to CEnemySoldier and by code that refers to CSkinnedCharacter. If you go and modify that code, you now need to consider that your changes aren't going to break CSkinnedCharacter or CEnemySoldier. That's quite a lot of extra dependencies, and it's something I'd consider particularly precarious because the dependency isn't obvious on the surface - you need to know that CEnemySoldier inherits from CSkinnedCharacter when you're changing the code.

And furthermore, if CSkinnedCharacter's principal purpose is to handle rendering, and you're talking about deriving from it but then replacing the rendering routine with your own stuff... well, then why derive from it at all? You wouldn't be using any of the stuff that you inherit.

It feels like inheritance should be the correct approach, because CEnemySoldier is-a CSkinnedCharacter. However, you can also spin things around a little and treat CEnemySoldier as a controller object - one that coordinates and controls other objects, like models and guns and sounds and so on. In that context, CEnemySoldier has-a CSkinnedCharacter, so composition is the appropriate relationship.

Share this post


Link to post
Share on other sites
TheTroll    883
In my opinion having to use globals means a bad design. There are ALWAYS other ways of doing it. When I first started programing, many, many years ago I would use a global here and there because it was much easier and seemed to be the right way to do it. As I learned I found out that there are better ways to accomplish the same things. Look at your design and figure out how to get rid of the globals.

theTroll

Share this post


Link to post
Share on other sites
Zahlman    1682
Quote:
Original post by superpig
It feels like inheritance should be the correct approach, because CEnemySoldier is-a CSkinnedCharacter. However, you can also spin things around a little and treat CEnemySoldier as a controller object - one that coordinates and controls other objects, like models and guns and sounds and so on. In that context, CEnemySoldier has-a CSkinnedCharacter, so composition is the appropriate relationship.


Yep.

But then, any time the name suggests a relationship that doesn't seem right in code, that name is suspect. So let's instead go with CCharacterSkin, or perhaps CSkinnedAvatar. :)

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