Advertisement

Again Inclusion question

Started by October 08, 2017 04:51 PM
29 comments, last by MarcusAseth 7 years, 5 months ago
7 minutes ago, jpetrie said:

Generally I create free functions to provide well-known constant values that cannot just be constexprs.

@jpetrie can you show me an example of one of this free function?

I would like to understand where my global variables should end up living, at which point during executing are they initialized, how this free functions get to them and how all the other files get to this free functions ^_^'

 

Simplest form is to create them inside main(), and pass them around as needed. You could make a class for them, so related variables are close together.

It's not a real global, but you have much more control over them, and you have to make explicit that some code relies on them, which will one day help in refactoring code (ie avoid the case that you got all parameters, and then find out code also has a huge number of dependencies on globals you completely forgot about.)

 

Advertisement
32 minutes ago, Alberth said:

Simplest form is to create them inside main(), and pass them around as needed.

Not a big fan of that, some object are just too widely used like App for requesting textures to it and Game to allow entity to interact with other entities in the game or the global paths to be used for loading and requesting textures to App (in the code above), I wouldn't want to pass this stuff down constructors and inheritance chains just to end up storing a pointer to each one of them inside of every object or something. And this in case I have understood what you are saying correctly, for me is always hard without a concrete code example to backup an explanation. :\

2 hours ago, MarcusAseth said:

Not a big fan of that, some object are just too widely used

That fact, that they are "widely used," is indicative of a design failure. In a non-trivially-sized project, there are very few things that actually "need" to be accessed from anywhere.

Passing dependencies around like Alberth is suggesting is the better way that making a ton of secret globals. It makes dependencies clear, allows you to enforce contracts in your interfaces, and so on. Globals are impossible to control effectively and impossible to reason about.

 

3 hours ago, MarcusAseth said:

can you show me an example of one of this free function?

 

"SomeThing getSomeThing() { return SomeThing(value, of, some, thing); }" if SomeThing has value semantics or "SomeThing& getSomeThing() { static SomeThing result(value, of, some, thing); return result; }" if it's more complex, et cetera.

 

@jpetrie sorry, still not clear ^_^' I guess I am missing the bigger structure here, where everything is placed in comparison to everything else, like in which header is this function compared to who calls it, where are the things result is builted with taken from and how you reach them and so on...


SomeThing& getSomeThing()
{ 
	static SomeThing result(value, of, some, thing);
	return result; 
}

so this above is the function.

So from what I am understanding, in practice would look something like this, and it will live in the Global.h:

Global.h


#include "App.h"
#include "SDL2\SDL.h" 

struct AppInfo {
		App* App;
		GameMode* Game;
		SDL_Window* Window;
		SDL_Renderer* Renderer;
		Uint32 Width, Height;
	};

AppInfo& GetAppInfo()
{ 
	static AppInfo result{MyApp.GetApp(), MyApp.GetGame(), MyApp.GetWindow(), MyApp.GetRenderer(), MyApp.GetWinWidth(), MyApp.GetWinHeight()};
	return result; 
}

But the problem is, when is that static initialized?! If it is when I run the program, then App wouldn't be initialized yet... is that the case? If so, then I still don't get it how to do it...

Furthermore, where is this "App MyApp"  global object created and initialized, I mean where is living? :\

The example is still too abstract for my brain, the problem is I can't see the entire structure pattern here... :\

Why not cut using "variables" completly for string constants and use some inline accessor function to grab it?


namespace MyGame
{
   namespace Constants
   {
      inline const char* Files() { return "./Assets"; }
      inline const char* OpenGl() { return "./Lib/OpenGl.dll"; }
   }
}

...
  
void* gl_lib = (void*)LoadLibraryA(MyGame::Constants::OpenGl());

Any clever compiler (and I think even MSVC should solve this) optimizes the inline call away for a pure string constant access without any considerable overhead

Advertisement

@Shaarigan if I understand correctly what you're saying, that's seems messy to me because then I have to compose in place the name of the thing I want to load like string(MyGame::Constants::Files()) + "Graphics/Checker.png" and I have to remember the name of stuff all over the place, much easier to just call Paths::Images::CHECKER and let it do the right thing.

1 hour ago, MarcusAseth said:

string(MyGame::Constants::Files()) + "Graphics/Checker.png"

Let it return a const std::string instead of a const char *. Then you can already slightly reduce it to

MyGame::Constants::Files() + "Graphics/Checker.png", which looks pretty reasonable (assuming you do not perform this a million times per second).

🧙

Just now, matt77hias said:

Let it return a const std::string instead of a const char *. Then you can already slightly reduce it to

MyGame::Constants::Files() + "Graphics/Checker.png", which looks pretty reasonable (assuming you do not perform this a million times per second).

Looks still pretty bad to me...All I am doing right now to load an image is this:



//Load Textures
LoadTexture(Paths::Images::CHECKER);

and to get it from another file,


Checker::Checker(float x, float y):
	Tile(x,y,Paths::Images::CHECKER)
{
}

The fact I write it in 2 different places increase chances for mistakes if I where to manually write it.

This way, I simply cannot make a mistake, and if I mispell it inside the Paths.h, then that error get caught by the LoadTexture.

4 minutes ago, MarcusAseth said:

The fact I write it in 2 different places increase chances for mistakes if I where to manually write it.

Fair point, but what if you want to change the directory of your assets? How many changes does that inccur at the moment?

You could also encapsulate your resources in some object which provides a method for retrieving the filename, file name and file path. And then you can pass a reference to the resource object around. This avoids the need for duplicating the concatenation everywhere.

🧙

This topic is closed to new replies.

Advertisement