Is it better to use extern or pass in a pointer (C++)

Started by
13 comments, last by lukesmith123 12 years, 7 months ago
My camera class needs to know about my level class for example.

Is it better to use extern level; for example or to create a pointer to a level object and set this pointer with function (setLevel(Level level);

is either "better" ? or is there specific reasons to choose between the two methods?

thanks,
Advertisement

My camera class needs to know about my level class for example.

Is it better to use extern level; for example or to create a pointer to a level object and set this pointer with function (setLevel(Level level);

is either "better" ? or is there specific reasons to choose between the two methods?

thanks,


What does the camera need to know about the level? It happens easily that one creates this kind of links between objects for some little thing even if the classes aren't really related.

Otherwise "SetLevel(...)" doesn't sound bad compared to the global variable.

Cheers!
It depends a lot on how complicated your program is and if you need to have others maintain the code (or if you anticipate maintaining it years from now). In most cases, it's just a bad idea to use globals if you can avoid it. kauna has the right idea though: even if you're not using globals you should make sure that your class dependencies are as well defined and simplified as possible.

I've found that even for relatively simple programs global variables can make life difficult. I find that I frequently shadow variables without knowing it (by reusing a global variable name in a local variable declaration), or forget that I have a global variable and pass it in under an aliased name as a parameter, or a dozen other bad things. It doesn't make the program any less correct, but it does make it notably harder to maintain.
Success requires no explanation. Failure allows none.
Extern is almost always a bad idea and unnecessary, more so than goto.

But you probably don't want either one.

Your camera is nothing to do with the level, so your basic idea is skewed a bit.

What you probably need is some static method you call to get the current level, as this will come up over and over making games.

So you have Level::getCurrentLevel() or you might have a LevelManager class that has the info which seems to be popular way to do things.

This is my thread. There are many threads like it, but this one is mine.

The others have already given the correct answer(s), but I want to draw special attention to one issue: If your camera class needs to know about your level, you are doing it wrong. That is a promise.
There is no reason for it, ever.
Likewise, a level never has any idea what a camera is. There are no conditions which could cause these two objects to know about the other.

Instead, one possible way to go (not exactly the way I would choose but certainly more appropriate) would be to have a camera that knows about certain non-specific data structures that it can use to speed up culling and therefor rendering, and the level just so happens to have these structures in it.
Then the camera knows only about a few generic structures, and any object, be it a level, a building interior, terrain, etc., can have these structures as part of their overall data.
And since there is still no logical reason a camera would know what a level is or vice-versa, the level would not be giving this data to the camera directly. The scene manager knows what both a level and a camera are and is responsible for sending whatever data needs to be sent to the camera from the level.
The camera doesn’t care from where the data came, and has no illogical dependencies.

In my example here, the camera is still doing a bit more than it should, but this puts you on a better track.

I've found that even for relatively simple programs global variables can make life difficult. I find that I frequently shadow variables without knowing it (by reusing a global variable name in a local variable declaration), or forget that I have a global variable and pass it in under an aliased name as a parameter, or a dozen other bad things. It doesn't make the program any less correct, but it does make it notably harder to maintain.

I am glad to see that you found globals difficult to maintain, but I am afraid it is for the wrong reason.
Standard naming conventions prevent name clashes. Globals typically start with g_, class members with m_, etc.
If you find yourself clashing names, you should think about how to prevent clashing of names (ala naming conventions).

However globals still cause a mess of code in most cases. In my newbie days I found myself #include’ing files just to get access to a global. But that file had a lot more in it than just the global, so my translation units were linking to a lot more information than they needed and making illogical connections. And, being a lazy newbie, I sometimes made use of those connections just because it was convenient. Sometimes I would add another global to that file so that one of my other sub-systems could augment how it worked with the original global, and suddenly every other system using that main global suddenly knew about the new global too, for no reason.
Circular dependencies and hackish work-arounds were not long to follow.

Naturally, I was excessive in my mistakes. Using globals does not mean you have to be as retarded with them as I was, but in the end there is still one common truth: The most simplistic connection between modules is via class declarations, not class instances. That is, by #include’ing only the class declaration, you are including only the bare amount of information you need, and this is always a better choice when your goal is to keep things as modular as possible.


Globals are still necessary for some things, but my approach is much more logical and adheres to the idea of #include’ing only the bare necessities.
My globals are actually static class members. Why is this better?
#1: It offers you the chance to make some hidden (as most are) and some public. Declaring a global inside a translation unit (not a header) may be valid, but given the choices, explicitly marking a global as “protected” or “private” really just seems more organized and logical. It also prevents hiding the fact that the global exists. I really prefer to look only at one header file to be able to determine, without exception, what things are declared.
#2: The “global” then becomes part of the class declaration. That means you are still only including the same file you would with the alternative, but only that file, and not a second file containing a global instance of that class.
#3: And because it is logically tied to that class declaration, no one will be tempted to add anything to that file that is not directly related to that class declaration. In the system I had used before, I had the class declaration and then another file for a global instance of that class. My global was not meant to be used specifically by any sub-system. I just thought of it as “whatever needs the main instance of this class can get it by #include’ing this file.” That flawed logic in itself lead to the spaghetti code that followed, but that cannot happen when a global is a static member of a class. It simply changes how people view the scope of the static member/global and no one will ever be tempted to add unrelated code/data to that file.
#4: Because of #3, you yourself will make better choices when deciding when and how to use globals. You won’t be putting a global there that is meant to be used by whatever needs a main instance of something. You will be putting static members/globals there because they are necessary for the basic workings of that class. This will hopefully make you think harder about when and where it is appropriate to use a global meant for random access. If you ever discover that case, please tell me. I still have not found any good reason to do so, and my code has been very clean and maintainable since dropping that idea.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

You can move any global into a static class member.

I constantly have to use other people's code that define a ton of constants as enums. Then the names change or disappear so I get a compiler error and NO idea what the thing is, why I have to pass it in (also terrible design), or even where it was declared. Who knows.

If instead you had something simple like

struct ColorConstants
{
static const long RED = 0;
static const long GREEN = 1;
static const long BLUE = 2;
}

it's easy to deal with changes, easy to fid the declaration, and totally avoids name clashes (and relying on just naming conventions alone is not going to be enough for a big complicated project).

This is my thread. There are many threads like it, but this one is mine.

YogurtEmperor's wall of text holds truth. Read it again. In particular, I want to quote
[color=#1C2837][size=2]
one possible way to go (not exactly the way I would choose but certainly more appropriate) would be to have a camera that knows about certain non-specific data structures ... any object, be it a level, a building interior, terrain, etc., can have these structures as part of their overall data.
And since there is still no logical reason a camera would know what a level is or vice-versa, the level would not be giving this data to the camera directly. The scene manager knows what both a level and a camera are and is responsible for sending whatever data needs to be sent to the camera from the level.
The camera doesn’t care from where the data came, and has no illogical dependencies.[/quote]I am doing exactly this. Cameras are opaque blobs, only the scene manager knows about them, it pulls out the info required by the world-drawing routines and sends the info by using an appropriate call.
[color=#1C2837][size=2]+1

Previously "Krohm"


You can move any global into a static class member.

I constantly have to use other people's code that define a ton of constants as enums. Then the names change or disappear so I get a compiler error and NO idea what the thing is, why I have to pass it in (also terrible design), or even where it was declared. Who knows.

If instead you had something simple like

struct ColorConstants
{
static const long RED = 0;
static const long GREEN = 1;
static const long BLUE = 2;
}

it's easy to deal with changes, easy to fid the declaration, and totally avoids name clashes (and relying on just naming conventions alone is not going to be enough for a big complicated project).

I'd prefer:

namespace SomethingColor
{
enum ColorConstants
{
RED,
GREEN,
BLUE
};
}

Identical syntax. Less worries about maintaining a set of unique integers. No weird object that somebody could instantiate.
I'm with Slavik81 on this one; in C++ if you are putting static members in classes you might want to consider a namespace instead.

Hell, with a namespace you can even have private global data if needs be, something I've used before.

[source]
// header

namespace Foo
{
void barSet(int value);
int barGet();
}

// cpp

namespace Foo
{

namespace
{
int barValue;
}

void barSet(int Value) { barValue = value; }
int barGet() { return barValue; }
}
[/source]

God aweful example but you get the idea...

Yes, it's 'global state' but it does have its uses.

The reason I was passing the level to the camera was because the camera wants to test collisions against the level. So the camera calls a function in the level whch tests for collision using th given arguments, cameras position etc.

I cant understand how I could do this without letting the camera know about the level?

This topic is closed to new replies.

Advertisement