Improper Global Instance of Class

Hi! I have a class called GUI. It is separated into a header and a CPP. (Both named GUI)

I want to make an instance of GUI called normalInterface, construct it automatically, and use it globally. (everywhere in the program, across multiple files) The GUI class has an Update function, which is what I need to use

At the bottom of GUI.h, I have this:

 
 extern GUI normalInterface


At the bottom of GUI.cpp, I have this:
 
GUI normalInterface("interface.png", "IS ALLOCATED");


However, when I try to do this elsewhere in the program:
 
normalInterface.update()


It does not work! I know for a fact that this class/update function does work, because when I create another instance of GUI within a function, and use it in that same function, it works. So I can do it internally - within a function.

But how do I make this global??? Thanks!
Assuming that there is a semicolon at the end of the declaration extern GUI normalInterface; it should work.

Perhaps you could post the contents of GUI.h and GUI.cpp (if they are not very large).

It would also help (greatly) if you could post the verbatim text of the error message.
It does not work!

How so? Please explain
a.) what you expected to happen;
b.) what happened instead

http://www.cplusplus.com/forum/beginner/1/
http://www.catb.org/esr/faqs/smart-questions.html

GUI.hpp:
1
2
3
4
5
6
7
# if ! defined PROJECT_GUI_HPP_INCLUDED
# define PROJECT_GUI_HPP_INCLUDED
# include <string>

extern struct GUI { std::string a, b; } normalInterface;

# endif 


GUI.cpp:
1
2
# include "GUI.hpp"
GUI normalInterface{"interface.png", "IS ALLOCATED"};


foo.cpp:
1
2
3
4
5
# include "GUI.hpp"
# include <iostream>
int main() {
  std::cout << normalInterface.a << ", " << normalInterface.b << '\n';
}
Well, I'm using SDL2.

The update function IS executed (I can tell by placing a cout function inside the update function) However, the update function is supposed to draw an image to the screen.

Here is my header:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class GUI {
public:

	image bkg;
	text displayHealth;
	text alert_displayHealth;
	text displayCurrency;
	string message;
	GUI(string name, string mess) : bkg(image(name)), message(mess) {}

	void update();
};

extern GUI normalInterface;


Here is my CPP:

1
2
3
4
5
6
7
8
#include "GUI.h"

void GUI::update() {
	bkg.drawBackground();
	cout << "DRAWN INTERFACE: " << message << endl;
}

GUI normalInterface("assets/system/interface/normalInterface.png", "IS ALLOCATED");


The console does print "DRAWN INTERFACE" but the background is not drawn. If this isn't a good forum for posting SDL questions, lemme know.
One possibility is that when GUI::update is called that the problem is in bkg.drawBackground();
Another problem might be that the image for the background might not be loaded properly - assumed there is a bitmap used for the background.
If this isn't a good forum for posting SDL questions, lemme know

There are not soo many people with knowledge about SDL but it's worth to try - unless you find a forum dedicated to SDL
You need to make sure that no SDL functions are used before you have called SDL_Init(). You might be able to delay the construction of the GUI object by making it a static local variable.

1
2
3
4
5
GUI& normalInterface()
{
	static GUI gui("assets/system/interface/normalInterface.png", "IS ALLOCATED");
	return gui;
}

Now the object would not get created until the first time that normalInterface() is called.
The console does print "DRAWN INTERFACE" but the background is not drawn.

If this was your problem, why did you open this thread by asking about global variables?

http://xyproblem.info/

Variables defined at namespace scope have static storage duration. Their constructors execute before main is invoked. If you are using SDL2 to load an asset in the constructor of a static object, you still need to ensure that the library is initialized before making any other API call.

Have you checked the library's error state?

Last edited on
If you are using SDL2 to load an asset in the constructor of a static object, you still need to ensure that the library is initialized before making any other API call.

Have you checked the library's error state?


Ahhhhh! I initialize SDL2 in my static build::buildGame() function. How can I have a global member of a class/variable of type GUI which is CONSTRUCTED in a specific spot? This way, I can construct my GUI after initializing SDL, but use it everywhere in the program.

Thanks for the responses so far! You guys are great!
You can use placement-new to avoid 2-stage initialization. Something like this:

Peter87's solution avoids this boiler-plate with a pair of extra parentheses as syntactic overhead, and no need to explicitly destroy things.

GUI.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# include <type_traits>
# include <new>
# include <utility>

struct gui {
  gui();
  ~gui();
};

namespace detail {
  using gui_buf_t = std::aligned_storage_t<sizeof(gui)>;
  extern gui_buf_t normal_interface_buf;
}

// NOTE: normal_interface may not be accessed until init_normal_interface is
// called.
extern gui& normal_interface;

template <typename... Args>
void init_normal_interface(Args&&... args)
{ new (&detail::normal_interface_buf) gui(std::forward<Args>(args)...); }
void destroy_normal_interface();


GUI.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# include "GUI.hpp"
# include <iostream>
gui::gui()  { std::cout << "gui::gui()\n"; }
gui::~gui() { std::cout << "gui::~gui()\n"; }

namespace detail {
  gui_buf_t normal_interface_buf{};
}

gui& normal_interface = reinterpret_cast<gui&>(detail::normal_interface_buf);

void destroy_normal_interface() {
  (&normal_interface)->~gui();
}


main.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
// # include "gui.hpp"
# include <SDL2/SDL.h>

int main() {
  if (SDL_Init(0x00) < 0) { return 1; }
  std::cout << "SDL_Init()\n";

  init_normal_interface();
  destroy_normal_interface();

  SDL_Quit();
  std::cout << "SDL_Quit()\n";
}
Last edited on
Topic archived. No new replies allowed.