I am working on a game,
I have a huge list of const global variables .h file which many .cpp file relies on.
(Enemies would like to know the max hp of players etc)
However, this is a compilation nightmare when any variable is changed in the file for game balancing.
I would like to prevent splitting up the files into multiple headers for the ease of the guy in charge of game balancing.
However, recategorizing is kind of a pain (clarity vs compile time, Player's maximum hp is used in many .cpp but it should belong to the PlayerVariables.h, including it in every file that uses it kind of destroys the purpose of splitting them up).
Is there a way to save some time other than the method above?
Just declare the global variables in the header file. And define them in another source file. That way if any of the values are changed only the globals.cpp needs to be recompiled since everything includes globals from the hpp.
In globals.hpp:
extern const unsigned PLAYER_MAX_HEALTH;
In globals.cpp:
#include "globals.hpp"
const unsigned PLAYER_MAX_HEALTH = 100;
You could try adding a configure-step with the preprocessor:
Only have preprocessor #defines in the config.h
Split it with the preprocessor into multiple headers only pulling in those definitions they need to declare actual const variables / enum-values / whatever.
Only copy those files which are different from the previous run over the previous version.
Optionally also have a glabals.cpp defining those symbols which might also need a definition.
Make sure to (re-)run make after the configuration was updated.
The advantage over just declaring external constant variables and defining and initializing them in a different translation-unit is constant-propagation and having proper compile-time-constants.
Related
In my folder I have a small version.cpp file with the following structure:
#include "thelibr/version.h"
const int major = MAJOR;
const int minor = MINOR;
I cannot understand what this code does and how is it used by the remaining part of the code (stored in other files of the same directory).
First, I understand that the code sets values of two variables (major and minor) but what is not clear to me is where the values of MAJOR and MINOR are set. Are they set in thelibr/version.h.
Second, it is also not clear to me when the above given lines of the code are executed. They are not put in any method that could potentially be called from other methods coded in other files. So, how these lines can be called?
Third, I see that string version is not present in any other file from the same directory. Does it mean that none of these file uses the code stored in the version.cpp. Shouldn't we include version.h file somewhere in other file to be able to use the code from the version.cpp?
Fourth, if we set the values of major and minor variables in the version.cpp, will these variables be visible somewhere else? It wonders me since we do not use any words like global or external.
C++ doesn't have a module system like Python where pure symbols may be exported and their values used in another source file. Instead it has header files: The contents of thelibr/version.h are essentially copy-pasted in place of the #include line. Anything inside that file is processed as if it were written out in the version.cpp file.
To export from one file to another (or to create libraries which can be interpreted by the linker or dynamic loader), use extern storage, which is the default for many things.
Deciding what is visible from one .cpp file to the next is rather complicated, but as a rule you cannot share compile-time values such as the version number; you can only share access to runtime objects such as the ints which store the version number.
To use major and minor from another .cpp file, you could declare in version.h:
extern const int major;
extern const int minor;
And then #include "thelibr/version.h" from the other file.
Many other questions deal with how to allocate a variable by declaring it in a header file and defining it (allocating) in a .cpp file.
What I want to do is not use any .cpp files for my class, and to define all functions as inline (in the header file). The problem that I run into is how to define static member variables so that even when the .h file is included in multiple compilation units I don't get the "first defined here" linker error.
I'm open to preprocessor hacks, etc. if it gets the job done. I just want to avoid any .cpp files.
If it matters I'm using GCC.
You can abuse the singleton pattern if you really must avoid any .cpp files:
class Foo {
public:
static Bar& getMyStatic() {
static Bar bar;
return bar;
};
};
This works because now the variable is a static variable inside a function, and static has a different meaning within a function context than within a class context. And for functions, the linker does recognize multiple identical definitions and throws away the copies.
But, of course, I would strongly advise against avoiding .cpp files: It means that you get into a situation where you have to build the entire program, or at least large parts of it, in one big piece. Every change you do will necessitate a complete rebuilt which slows down your change-compile-test cycle significantly. For very small projects that might not be a problem, but it is for medium to large ones.
With static variables you have to put in a .cpp file to avoid the possibility of multiple static variables when the intention is to have just the one. Besides it is not a good idea to have large inline methods as it is only a hint to the compiler but also makes compilation take longer (you change some of those functions in development and then lots of dependent files will need to get compiled!)
However if you do not want lots of .cpp files with just a few statics in it why not have just one file to store them in.
As long as you only include that header file once in your whole project, you'll be OK. However, that's a pretty strong requirement, and can be difficult to make others adhere to.
You could have a static variable, but that means you have more than one for the entire program, which may or may not matter (bear in mind that you can't change it in the future, so you may have what's known as a "latent bug" - you change some other code, and all of a sudden you have created a new bug, because the variable isn't ONE variable).
I have a multi-file program consisting of
main.cpp
ext1.cpp
ext2.cpp
ext3.cpp
vars.h
As the name suggests, main.cpp is the main file, extX.cpp contains various functions and vars.h some global constants.
However, in main.cpp there are also (a few!) variable declarations, but they must only be within the scope of main.cpp -- that is why I haven't placed them in vars.h
I want to reduce the amount of code in main.cpp (for clarity-issues). I am looking for a way to declare these variables inside a header of some sort, but in a way that it is only visible to main.cpp.
Is it correctly understood that if I place them all inside e.g. vars_main.h (with no external keyword) and just include "vars_main.h", then I have achieved my goal?
Is it considered to be "correct" C++-style to do it this way?
If those variables are used only in main(), then yes, you could do that. But I would not go as far as considering it a "correct C++ style".
If one day you will end up including that header file into another translation unit (maybe because you will need to share just one of those variables), the linker will start complaining about multiple definitions.
At that point, to overcome this, you could use the static keyword to give those variables internal linkage and workaround the problem of multiple definitions. This way, however, each translation unit (.cpp file) will hold its own copy of those variables, which is probably not what you want, especially if they are not constant - just for the record, global constants have internal linkage by default, so you won't need to explicitly qualify them as static.
The normal practice here is either to leave those variable definitions in main(), or to have one header which contains only extern declarations of those variables, and one translation unit that contains their definitions. Then, all the files which need to access those variable would just import the header with the declarations.
The usual practice would be to go ahead and define them in main.cpp, since they're in a distinct block and won't affect the readability of the code. However you can certainly move them out to a separate include file that's only included in one .cpp, that's a stylistic choice that's completely up to you.
If the variables you are talking about are global variables private to main, I think that you should let them in main.cpp. If they are not used anywhere else, it does not make sense to declare them in a header
You could also create a class implementing the "main" features with your variables in private scope so that they won't be used by other parts of the implementation .
I have a number of C++ classes, alot of them (not all) share two "static size variables" e.g.
share.h
/*Other variables in this header used by all classes*/
static size width=10;//Used by about 60%
static size height = 12;//used by about 60%
So I placed them in a header file along with other objects that all classes share.
when I compile the project I get alot of warnings (from the classes which dont use these), which complain about them being defined and not used. But I need them there!
So I ask, is there a way to hash these to prevent such warnings?
Hashing them so that they can be defined! preventing warnings from classes calling this header file which dont require these last two variables, but they call header because they need everything else init
You should place them in an individual header file. So you can include it only in the classes they need it. This avoids the warning in the other classes. So in the end you will have two header files. One where the stuff for all classes is included and another where the variables which are not used in all are defined.
However try to avoid global variables.
Edit reading tune2fs' answer, I realized I may have interpreted the question wrong.
Perhaps you forgot to use extern in the header file? If you just include static definitions in the header file all compilation units will have unique copies, not shared. See also this explanation of static/extern
Edit Disambiguated in comments
static SomeClass NotUnusedInstance;
static void unused_vars_helper()
{
static SomeClass* take_address = &NotUnusedInstance;
}
This approach is design to have minimal impact (not invoking any actual code; take_address isn't actually initialized unless you call unused_vars_helper).
This should work pretty well for your case. You can make unused_vars_helper() static and/or move it inside an anonymous namespace to prevent external visibility of the helper.
We have these set of "utility" constants defined in a series of file. The problem arises from the fact that TOO MANY files include these global constant files, that, if we add a constant to one of those files and try to build, it builds the whole entire library, which takes up more than an hour.
Could anyone suggest a better way for this approach? That would be greatly appreciated.
First, if you are defining them directly in the header, I'd suggest instead delcaring them extern const, and then defining them in a cpp file:
//in .hpp:
extern const std::string foo;
//in .cpp:
const std::string foo = "FOO";
That way, at least definitions can be changed without a rebuild.
Second, examine where they are being included. If the constant file is being included in a low level header, can the include be moved to the cpp instead? Removing it might lower the coupling so it doesn't have to rebuild as much.
Third, break up that file. I'd suggest mapping out a structure you'd eventually want, start adding new constants to the new structure instead of the old file. Eventually (when you are sure you've got the structure you want), refactor the old file into the new structure, and make the old file include the entire structure. Finally, go through and remove all includes of the old file, pointing them at the appropriate new sections. That'll break up the refactoring so you don't have to do it all at once.
And fourth, you might be able to trick your compiler into not rebuilding if the header file changes. You'd have to check your compiler's documentation, and it might be unsafe, so you'd occasionally want to add full builds as well.
Do you really need every global define to be included in every file? You should probably split the constants up into categories and then split them into different files.
Every .h that is included is simply copied at that point in the file that is including it. If you change something in a file (either directly or via changing something that is included) then it absolutely needs to be recompile.
Another solution would be to have a .h file that has an accessor to a map of string name/values. Then in the .cpp file of that map/accessor you can insert the new values. Every new value you put would only need 1 file to be recompiled.
Another solution is not to include the header file anywhere. Simply extern in the variables you need in each .cpp file.
Perhaps it's time to do some refactoring to improve the cohesion and reduce the coupling in your software design. Splitting the global constant files would allow modules to be more selective about which constants need to be included, which will eliminate some of the
unnecessary coupling. In the extreme case, you could break it all the way down to one constant per file, and ensure that each module only includes the constants it needs to use.
But that could result in poor cohesion, in the sense that the constants might naturally fall into related groups, such that a module that requires one constant will generally also
require many others from that group. So the trick is to find a better grouping of constants in the various global files, then ensure that each module only includes what it needs.
(Edit: I didn't think of external constants. Indeed, my idea is kinda stupid.)
(Edit: My "stupid" macro idea actually saves build time for when constants are added. Thanks for pointing that out, Brian!)
Use parallel building :-)
Seriously, I think one solution would be to create another header called utility_ex.hpp or something where you add new constants that you occasionally merge into utility.hpp (or whatever your current utility constants header is called).
Another (less efficient) solution would be to have a macro like this:
#define constant(name) get_constant(#name)
// # means turn name into a string literal
int get_constant(const char *name);
Now suppose you want MAX_CUSTOMERS to be defined as 100. You can say:
constant(MAX_CUSTOMERS)
in the code. In get_constant's code, you might have:
int get_constant(const char *name) {
if (!strcmp(name, "MAX_CUSTOMERS"))
return 100;
//shouldn't happen
return -1;
}