2

I'm working on a small software project which I hope to release in the future as open-source, so I was hoping to gather opinions on what the best currently accepted practices are in regards to this issue.

The application itself is procedural, not object oriented (there is no need for me to encapsulate the rendering functions or event handling functions in a class), but some aspects of the application are heavily object oriented (like the scripting console, which heavily relies on OO). The OO aspects of the code have the standard object.cpp and object.h files.

For the procedural part, I have my code split up into various files (e.g. main.cpp, render.cpp, events.cpp), each which might have some global variables specific to that file. I also have corresponding header files for each, defining all functions and variables (as extern) that I want to be accessible from other files. Then, I just #include the right header when I need access to that function/variable from another source file.

I realized today that I could also have another option: create a single globals.h header file, where I could define all global variables (as extern again) and functions that would be needed outside of a specific source file. Then, I could just #include this file in all of the source files (instead of each individual header file like I do now). Also, using this method, if I needed to promote a variable/function to global (instead of local), I could just add the entry to the header file.


The Question: Is it a better practice to use a corresponding header file for every single .cpp file (and define the variables/functions I want globally accessible in those headers), or use a single header file to declare all globally accessible variables/functions?


Another quick update, most (but not all) of the globals are used as such because my application is multithreaded.

Breakthrough
  • 2,444
  • 2
  • 23
  • 37
  • 1
    Why is this tagged "C"? Decide on a language. "All the global variables" is bound to elicit some reactions if this is C++. – Kerrek SB Aug 26 '11 at 15:33
  • I'm creating the program in C++, but it has bindings to Lua and SDL (which were both written in C). I also wish to extend this practice to another application I'm writing for an embedded system (in C). The main flow of the program is procedural (no singleton objects), so I do need global variables. – Breakthrough Aug 26 '11 at 15:35
  • Just declaring all global variables in `globals.h` as **extern** doesn't give definitions for it. You should define them in at least one source file. Or else linker will complain on the **extern** variables usage. – Mahesh Aug 26 '11 at 15:36
  • @Mahesh sorry, I should have been more explicit in that. Yes, the variables are defined **only** in the source file. I only include the `extern` keyword when I need to access them from another source file. – Breakthrough Aug 26 '11 at 15:37
  • @Breakthrough - Then that is a good way to do it. However, I discourage usage of global variables if at all you have no other choice. – Mahesh Aug 26 '11 at 15:39
  • It is better practice *not* to define globally accessible variables in C++. You may want to rethink your design if this is a new project, and determine whether the global data is better off being owned by some class. There are certain cases where the only options are singletons or global data, but if you're looking at doing this in every C++ header file there is definitely something wrong with the design. – Praetorian Aug 26 '11 at 15:39
  • @Praetorian it's a fairly simple 3D application. I just don't see the point in encapsulating my rendering functions, event functions, etc, in a class (or singleton). I'm trying to keep it as low-overhead as possible, so I figured globals would be the best way to do it here. Again though, this is why I'm asking. Should I have a single file to keep all of my application-wide globals (variables and functions) in one place, or keep them in their respective header files? – Breakthrough Aug 26 '11 at 15:42
  • Also, @Kerrek SB, why is the use of globals so discouraged, when the use of a singleton is [just as discouraged](http://stackoverflow.com/questions/86582/singleton-how-should-it-be-used/92193#92193)? Isn't the use of globals (and namespaces where appropriate) less overhead then encapsulating all of your functions and variables in a class? – Breakthrough Aug 26 '11 at 15:46
  • 2
    @Breakthrough: It's all about design. No, not everything *has* to go inside a class, heaven forbid, we don't want.com.another.java.wtf. But modularity and locality are crucial to clean design, and globals and singletons go against that. It's not to say that sometimes a global gets the job done, but it shouldn't be a matter of course. It's very hard to discuss efficiency abstractly, but I don't see why you shouldn't be able to call C-library functions just as efficiently with local automatic variables. – Kerrek SB Aug 26 '11 at 15:49
  • @Kerrek SB I agree with you, and I agree that modularity is crucial to the design of any program... I have thought this program out before though. The console side of the program is **heavily** object-oriented, since that part needs tons of modularity. But for the rendering aspect, not so much. Why encapsulate the four colours my render manager needs, when I can just globally access and modify them when need be? Why encapsulate my event handler when it only requires three functions (and a five globals)? These are the issues I'm questioning, and the best practices to deal with each of them. – Breakthrough Aug 26 '11 at 15:55

4 Answers4

3

To me it is way better to have a header file corresponding to each implementation (c or cpp) file. You must think your classes, structures and functions as modules, and if you split your implementation, it is logical that you split your delarations too.

Another thing is that when you modify a header file, it leads all files that include it to be recompiled at build time. And at the end I can tell you it can take long. You can avoid rebuilding everything by properly splitting your declarations.

Shlublu
  • 10,917
  • 4
  • 51
  • 70
  • +1, but let's say I remove a global that is used in `x.cpp` but **not** in `y.cpp`. Wouldn't the compiler realize that nothing has changed with respect to `y.cpp` and avoid re-compiling the object file, or do compilers rely on raw source code modifications (since in essence, `#including` a header just dumps the raw code in there)? – Breakthrough Aug 26 '11 at 16:03
  • @Breakthrough: The compiler doesn't realize nothing's changed to `y.cpp` because it never sees _just_ `y.cpp`. It sees `globals.h` + `y.cpp` because they've already been put together by the preprocessor. To the compiler, a change to `globals.h` looks like a change to _every_ file that includes `globals.h`, hence the recompilations. – Steve Blackwell Aug 26 '11 at 16:16
2

I would recommend having more headers and put less in them. You have to have the litany of includes, but that is simple to understand and edit if its wrong.

Having one big globals is harder to cope with if something goes wacky. If you did have to change something, that change is potentially far reaching and high risk.

More code isn't a bad thing in this case.

A minor point is that your compile times will increase super linearly the more you put in that one big header since each and every file has to process it. On an embedded project it is probably less of a worry, but in general having a lot in headers will start to weigh you down.

Tom Kerr
  • 10,444
  • 2
  • 30
  • 46
  • 1
    +1, thanks for the response Tom... much appreciated. This answer is just as valid as the one @Shlublu posted, but he answered quicker, so I had to accept his. – Breakthrough Aug 26 '11 at 16:24
1

It's better to put them all in one file and not compile that file at all. If you have global variables you should be rethinking your design, especially if you're doing applications programming and not low-level systems programming.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
0

As I've said in the comments below the question, the first thing to do would be to try and eliminate all global data. If this is not possible, rather than one big header, or throwing externs into each class' header, I'd follow a third approach.

Say your Event class needs to have a global instance. If you declare the global instance in event.cpp and extern it in event.hpp, then this essentially makes these files non-reusable anywhere else. Throwing it into a globals.cpp and globals.hpp is not ideal either because every time that global header gets modified, chances are your entire project will be rebuilt because the header is being included by everyone.

So the third option is to create an accompanying header and source file for each class that needs to have a global instance. So you'd declare the Event global instance in event_g.cpp and extern it in event_g.hpp.

Yes, it is ugly, and yes, it is tedious. But there's nothing pretty about global data to being with.

Praetorian
  • 106,671
  • 19
  • 240
  • 328