Sign in to follow this  

Initialisation problems

This topic is 3486 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 seem to have a problem with some classes being initialised/created. I have two GUI screen classes which contain all the UI controls for that particular screen (the two in question are main screen and player select screen). I declare a static pointer to each in the .h file where their classes are defined. I then create the classes in a function:
/* Creates the User Interface screens for the menus */
inline void createUIScreens() {
    mainScreen = new MainScreen();
    playerScreen = new PlayerScreen();
    mainScreen->setVisible(true);  // Show title screen
}

setVisible simply sets the screen to draw. The problem i have is that when i try to display playerScreen, it won't work. Specifically, playerScreen is NULL. The strangest thing is that playerScreen->setVisible(true); is actually called, i don't get an access violation (null pointer exception). Both screens inherit from class Container, which is the super class for all UI windows/screens.
class Container : public Component {
    ...
    inline void setVisible(bool b) { Component::active = (b ? this : NULL); }
};


class Component {
public:
    static Component* active; // The component that is active
    ...
};

As you can probably see from the above code, active is set to the Container that calls setVisible(true). It is a pointer to the Container (screen) to draw, and is set to NULL if nothing is visible. This may not be the best way to do it but it's the way i'm doing it. My problem is that when i call playerScreen->setVisible(true);, playerScreen is NULL yet the function still get's called and (as far as i know) 'this' is NULL; When i outputted some debug values i found that playerScreen & mainScreen were NULL when initialised, then set to some value (the pointer that is) when they were created, and then went back to NULL when i called playerScreen->setVisible(true);. Any ideas? thanks

Share this post


Link to post
Share on other sites
Yes, i read about that a while ago from Thinking in C++. But i didn't think that applied in my case since i call createUIScreens() from main (WinMain) and i call playerScreen->setVisible(true); after it. So i didn't think that it was an initialisation problem but it seems that it is (hence the title of my post). I should mention that i call setVisible from Windows event proc but that shouldn't matter.

EDIT: I should probably post the code for the declaration of the variables. I already mentioned that they are pointers but here is the actual code:

#ifndef _UISCREENS_H_
#define _UISCREENS_H_

#include "gui/gui.h"
using namespace gui;

class MainScreen;
class PlayerPanel;
class PlayerScreen;

//// Declarations here //////////////////
static MainScreen* mainScreen = NULL;
static PlayerScreen* playerScreen = NULL;
/////////////////////////////////////////

class MainScreen : public Container, public ActionListener {
...
};
class PlayerScreen : public Window, public ActionListener {
...
};

/* Creates the User Interface screens for the menus */
inline void createUIScreens() {
mainScreen = new MainScreen();
playerScreen = new PlayerScreen();
mainScreen->setVisible(true); // Show title screen
}

#endif // _UISCREENS_H_

Share this post


Link to post
Share on other sites
static at global scope means one copy per translation unit, which means that if two different cpp files include your header they each get different copies of mainScreen and playerScreen, almost certainly not what you want. Replace static with extern and define your variables in one cpp file, or better yet, get rid of the globals altogether.

Also note that your include guard is illegal. Identifiers starting with an underscore followed by a capital letter (or containing consecutive underscores) are reserved.

Σnigma

Share this post


Link to post
Share on other sites
Quote:
Original post by Enigmastatic at global scope means one copy per translation unit, which means that if two different cpp files include your header they each get different copies of mainScreen and playerScreen, almost certainly not what you want. Replace static with extern and define your variables in one cpp file, or better yet, get rid of the globals altogether.

Man, there is so much i don't know about C++. I thought that static at global scope meant that the variable is only defined once instead of each time the header file is included, which is right but i didn't know that each cpp file gets a separate copy. I will try using extern and defining the variables in the respective cpp files where the classes are defined.

Quote:
Original post by Enigma
Also note that your include guard is illegal. Identifiers starting with an underscore followed by a capital letter (or containing consecutive underscores) are reserved.

Really!? I have used it like that since i started programming in C++ and it has worked fine for me. Is there any compiler that it won't work on or are you just saying that it's bad programming practice? And i use the underscores at the front and back because the identifier is reserved, for header file guards. Any other capital letter identifiers are used for constants.

EDIT: yay, it worked. thanks. It's probably not the most elegant solution (extern variables defined in the cpp file where the class is defined) but it works so i'll leave it at that for now.

Share this post


Link to post
Share on other sites
Quote:
Original post by XTAL256
EDIT: yay, it worked. thanks. It's probably not the most elegant solution (extern variables defined in the cpp file where the class is defined) but it works so i'll leave it at that for now.


Elegant or not, it's the proper solution. If you only want a global variable once, it must only appear in one place. A header file is copy-and-pasted wherever it's #included so that is very unlikely to be 'one place'.

Share this post


Link to post
Share on other sites
It's just the way Enigma said "...or better yet, get rid of the globals altogether" made me think that global variables weren't the best solution. Although i understand that there would be cases where it is the best and only way.

Share this post


Link to post
Share on other sites
Getting rid of globals is best, yes. But if you want globals, putting them in a single .CPP and referencing them via an extern declaration in a header is the only reasonable approach.

Share this post


Link to post
Share on other sites
Quote:
Original post by XTAL256
Really!? I have used it like that since i started programming in C++ and it has worked fine for me. Is there any compiler that it won't work on or are you just saying that it's bad programming practice? And i use the underscores at the front and back because the identifier is reserved, for header file guards. Any other capital letter identifiers are used for constants.
I'm not aware of any compiler which disallows all such identifiers, but there certainly exist compilers that use identifiers like that internally and will stomp all over you if you happen to clash with them. You might never hit one of those situations, but why take the risk?

Σnigma

Share this post


Link to post
Share on other sites
Quote:
Original post by XTAL256
Yes, i read about that a while ago from Thinking in C++. But i didn't think that applied in my case since i call createUIScreens() from main (WinMain) and i call playerScreen->setVisible(true); after it. So i didn't think that it was an initialisation problem but it seems that it is (hence the title of my post).


Sorry to misinform, I didn't read your post closely enough :)

Share this post


Link to post
Share on other sites
Quote:
Original post by fpsgamer
Sorry to misinform, I didn't read your post closely enough :)

Don't worry about it, at the time i posted i didn't really know what the problem was. Although i was quite sure it wasn't the static initialization order fiasco i couldn't be certain.

Share this post


Link to post
Share on other sites
Do you really need to create "screens" ahead of time? Do you even really want to do so? Doesn't it make more sense to "create" an in-game screen at the time that the game is launched - i.e. when you have gathered information about the game to play?

And do you really want to set each screen's "visibility" as a property of it? Shouldn't there always be one specific screen that is visible? Don't you think it will become a maintenance headache to ensure that?

Solution: instead of holding pointers to "each" screen, just hold one to the currently visible screen. When the visible screen needs to change, destroy and replace the old screen object.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Do you really want to set each screen's "visibility" as a property of it? Shouldn't there always be one specific screen that is visible? Don't you think it will become a maintenance headache to ensure that?

The problem with that is when i have a smaller screen (i.e. dialog box) on top of another screen. My design isn't set in stone, if it's easier to do it your way i will do that.

Quote:
Original post by Zahlman
Solution: instead of holding pointers to "each" screen, just hold one to the currently visible screen.

That's what static Component* active; is, a pointer to the currently active (and visible) screen. But i didn't want to create screens each time they are used because that would be (slightly) slower, plus i need global variables so that one screen can change to another when a button on the first screen is pressed.

Share this post


Link to post
Share on other sites
Quote:
But i didn't want to create screens each time they are used because that would be (slightly) slower
You don’t have to. You can keep around the most frequently used or most probable to be used screens. Destroy the ones that most likely will never be seen again (such as an options screen), or haven’t been visited in ages.

Quote:
plus i need global variables so that one screen can change to another when a button on the first screen is pressed.
I don’t see why. Also, think about the implications for the argument you are making here. For you to handle any sort of screen flow, must all the relevant global variables be defined? What if you wanted to dynamically create a screen? Is it then impossible, because you don’t have the appropriate global variables?

If you solution to something is throw out globals, it probably means you didn’t design properly.

Share this post


Link to post
Share on other sites

This topic is 3486 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.

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