10

I frequently have to write c/c++ programs with 10+ source files where a handful of variables need to be shared between functions in all the files. I have read before that it is generally good practice to avoid using global variables with extern. However, if it is completely necessary to use global variables, this link provides a good strategy. Lately, I have been toying with the strategy of wrapping up all my variables in a struct or a class and passing this struct around to different functions. I was wondering which way people consider to be cleaner and if there are any better alternatives.

EDIT: I realize strategies may be different in the two languages. I am interested in strategies that apply to only one language or both.

Community
  • 1
  • 1
baconeer
  • 211
  • 1
  • 2
  • 7
  • 5
    I would argue that this is not a C/C++ question, but a C OR C++ question. Your options and best practice are pretty different in the two languages. – Joe Aug 01 '13 at 15:42
  • Why is it bad practice to use global variables? In C++ one could argue that you should use the object approach, so global variables should be replaced by attributes, but in C I do not see the problem. – Shaac Aug 01 '13 at 15:44
  • "I have been toying with the strategy of wrapping up all my variables in a struct or a class and passing this struct around to different functions." Very good, this is one good way to avoid globals. – bames53 Aug 01 '13 at 17:52

5 Answers5

4

Pass around a class/struct of "context" data instead of global variables. You will be suprised how often a global variable becomes no longer global, with different modules wanting to use different values for it at the same time.

Neil Kirk
  • 21,327
  • 9
  • 53
  • 91
  • `with different modules wanting to use different values for it at the same time` Unless you use a singleton with mutexes and semaphores to avoid *deadlocks* and *livelocks* respectively. – gifnoc-gkp Aug 01 '13 at 16:33
  • This is nothing to do with multithreading. Suppose you have a global variable screen resolution. But then later on you want to support two windows. It's not easy to add that if you hardcoded everything to the same global variable. – Neil Kirk Aug 01 '13 at 17:14
  • It has everything to do with multithreading. Don't get me wrong. I didn't say *use a singleton instead of global variables*. I said **wrap** your global variables around it. Of course you should avoid global variables in the first place but if you want to go global *singletons are the way to go*. – gifnoc-gkp Aug 01 '13 at 17:20
  • What are you talking about? My answer is NOT to use global variables. – Neil Kirk Aug 01 '13 at 17:24
  • By different values I am not refering to different values written to the same variable by different threads. I am talking about a single instance of a variable no longer being sufficient. – Neil Kirk Aug 01 '13 at 17:26
  • `I was wondering which way people consider to be cleaner and if there are any better alternatives` You're answering HALF the question – gifnoc-gkp Aug 01 '13 at 17:27
  • By the same logic your answer is incomplete because you discuss a thread-safe alternative to global variables but you do not discuss a thread-safe alternative to a passed context struct. – Neil Kirk Aug 01 '13 at 17:32
2

My take in C++

I found it a good practice in C++ anyway to limit the scope of my global variables with a namespace. That way you can eliminate any ambiguity between your 10+ source files.

For example:

namespace ObjectGlobalVars {
   //Put all of your global variables here
   int myvariable = 0;
}

//And then later on you can reference them like
ObjectGlobalVars::myvariable++;
JBL
  • 12,588
  • 4
  • 53
  • 84
Kirk Backus
  • 4,776
  • 4
  • 32
  • 52
2

Does it REALLY need to be global?

This is the first question you should always ask, is this variable used GLOBALLY e.g. in all contexts. The answer is almost certainly... no it's not.

Consider Context

Is the variable global state, or is it context? Global state is usually rare, context on the other hand is quite common. If it's global state consider wrapping in a singleton so you can manage the how of interaction with your globals. Using Atomic<> is probably not a bad idea, you should at least consider synchronization.

If it is context then it should be passed explicitly in a structure or class, as the data is explicitly relevant to that context an no-other. Passing context explicitly may seem like a burden but it makes it very clear where the context is coming from rather than just referencing random variables out of the ether.

What is the Scope?

It may seem odd to say that globals are scoped, but any global declared in a single file may be declared static and thus unlinkable from any other file. This means you can restrict who has access to the global state in a given scope. This allows you to prevent people from randomly tweaking variables.

Community
  • 1
  • 1
Mgetz
  • 5,108
  • 2
  • 33
  • 51
2

The better alternative to globals is to not use globals.

Don't try to sweep them under the rug using a struct or a namespace or a singleton or some other silly thing whose only purpose is to hide the fact that you're using globals.

Just don't ever create one. Ever.

It will force you to think of ownership and lifetime and dependencies and responsibility. You know, grown-up things.

And then, when you're comfortable writing global-free code, you can start violating all those rules.
Because that's what rules are for: to be followed, and to be broken.

molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • 7
    **So to summarize your post:** *Learn to code, use globals later.* I don't believe that's useful to him. – gifnoc-gkp Aug 01 '13 at 16:39
  • 1
    I guess I should have asked the question in the context of someone who already has a good understanding of coding in general and is just trying to clean up coding habits. – baconeer Aug 01 '13 at 17:25
1

In c++
Having global variables lying around here and there, is an example of bad code.
If you want to share things on a global scale, then group them up and follow the singleton pattern.

Example:

class Singleton
{
    private:
        int mData;

    public:
        static Singleton& getInstance()
        {
            static Singleton instance;
            return instance;
        }
        int GetData()
        {
            return mData;
        }
    private:
        Singleton() {};
        Singleton(Singleton const&);
        void operator=(Singleton const&);
};

Advantages:

  • Only 1 global variable. The instance of our singleton.

  • You can include mutex / semaphore mechanisms inside the singleton, for thread-safe access of it's members.

  • Restricts the access of it's members helping you avoid logical and synchronization flaws.

Disadvantages:

  • Harder to implement. - If it's your first time -



In c
You should avoid declaring global variables, pass them in structs instead.

For instance:

struct MyData
{
    int a;
    int b;
};

void bar(struct MyData* data)
{
    data->b = 2;
}

void foo()
{
    struct MyData mdata;
    mdata.a = 1;

    bar( &mdata );
}



To sum things up
Having global variables lying around should be avoided as much as possible, in both languages.

gifnoc-gkp
  • 1,506
  • 1
  • 8
  • 17
  • You have a good point, but you **have to be careful** that it's not null, or that it's created only once. Not recommended for newbies :) – Iosif Murariu Aug 01 '13 at 15:51
  • @losifM The whole point of a singleton is to be created once. – gifnoc-gkp Aug 01 '13 at 15:58
  • I know, but you'd be surprised of how many show up to an interview and mess the singleton pattern up. – Iosif Murariu Aug 01 '13 at 16:03
  • 1
    @losif M. I agree; but once you get it right, you're writing better code. – gifnoc-gkp Aug 01 '13 at 16:05
  • The best way not to mess up the singleton pattern is not to use singletons :D – Neil Kirk Aug 01 '13 at 16:09
  • 1
    The "In C" section applies equally to both languages. Only use a singleton if you really, really want a global for some reason. Also, beware that this implementation doesn't solve all the lifetime issues associated with globals: the object is guaranteed to be created before first access, but may still be accessed by other static objects after it's destroyed. – Mike Seymour Aug 01 '13 at 16:15
  • There's was book about the common pitfalls using singletons. I'll search and add it. – gifnoc-gkp Aug 01 '13 at 16:19
  • Singletons are no better than global variables. Sharing variables does not require either a singleton or global vars. – bames53 Aug 01 '13 at 16:24
  • @bames53 It's true that sharing variables do not require a singleton but they're better than global variables. Singletons allow you to group the variables you want to have a global scope under a thread-safe bubble, while avoiding redefinitions. – gifnoc-gkp Aug 01 '13 at 16:31
  • In C why is passing a struct prefered to a global variable when neither are thread safe? – Neil Kirk Aug 01 '13 at 17:33
  • Why is this not a concern when making a singleton? – Neil Kirk Aug 01 '13 at 17:43
  • @TheOtherGuy It's possible to group global variables and add thread safety in other ways as well, but they're still global variables. Singletons are as bad as globals because they effectively are globals. – bames53 Aug 01 '13 at 17:43
  • @bames53 I never said that they cease to be global variables. Excuse me but I don't get the second part. – gifnoc-gkp Aug 01 '13 at 17:44
  • You can't redefine a global variable either, surely the linker will complain. – Neil Kirk Aug 01 '13 at 17:45
  • The question is NOT about the best way to implement global variables. The question is whether to use global variables or pass a context struct. You give a different answer for C and C++ with no explaination why. – Neil Kirk Aug 01 '13 at 17:47
  • @NeilKirt `What is the best strategy for sharing variables between source files in c/c++?` Then he proceeds giving information about patterns he tried. – gifnoc-gkp Aug 01 '13 at 17:49
  • @NeilKirk Following the same logic I could just answer `none`. – gifnoc-gkp Aug 01 '13 at 17:49
  • Hey you were the one fussing on my answer. I never said it was perfect but neither is yours. – Neil Kirk Aug 01 '13 at 19:03
  • @Neil Kirk At least my answer wen't in depth examining other concepts rather than answering with a generalized `no use that instead`. I believe your C coding style is not letting you see the whole picture. Singletons aren't bad, structs are not bad either. But Singletons are cleaner and in the end most projects resort to them. Instead of arguing wether it is good to use a Singleton to wrap globals or not (which isn't even an debate since most real-world application use them already) you should look into improving your answer. – gifnoc-gkp Aug 01 '13 at 19:19
  • @TheOtherGuy You really don't get it. I am not even a C programmer. I never said singletons are bad. Singletons are better than global variables. But the question was about alternatives to global variables, not JUST improvements to them (Have you really read the question?). It's like he asked whether to use a boat or a car. You say boat, I say car. Fair enough. Then you critisize my answer by saying a speedboat is better than a boat, so a speedboat is better than a car. It's a completely different approach. – Neil Kirk Aug 01 '13 at 19:30
  • I worked in a project which had some global variables. Then we needed to split off some parts of the program state into a different bubble, with their own set of global variables. As they were hardcoded to use a specific global variable or singleton that was impossible. We had to create state context objects passed to the objects instead. A singleton is a special kind of state context technique which only allows one state. Sometimes you need more. – Neil Kirk Aug 01 '13 at 19:34
  • @Neil Kirk Having global variables is a good coding style *only* when you know that they won't be part of the inner calculations. If you're instansiating global variables to hold information about a certain calculation that might be moved or templated then you're doing a big mistake. Singletons like any other global variables shouldn't ever have to be moved or copied. That's why our company uses singletons for `World` or `Engine` classes and not `Car` or `HelperClass`. The above comment is an example of a future-planning failure. – gifnoc-gkp Aug 01 '13 at 19:49
  • @Neil Kirk That's why my answer resulted into saying that you shouldn't use globals at all if possible. Because incompetent coders can mess the codebase. But hey, you didn't even take time to read my answer. – gifnoc-gkp Aug 01 '13 at 19:50
  • A singleton is conceptually the same as a global variable, it is just more robust. That's why I don't understand why "singleton > global variable" is relevent to my suggestion not to use singletons or global variables and use context objects, which is what I put in my answer you first commented on. – Neil Kirk Aug 01 '13 at 19:53
  • I never said that global variables is relevant to passing structs. You said singletons = global variables which is partialy true but hiding the truth which its robustness and flexibility. – gifnoc-gkp Aug 01 '13 at 19:55
  • What were your comments on my answer going on about? Refering to your other comment which I didn't see before, what happens if you want two Worlds at the same time? – Neil Kirk Aug 01 '13 at 19:57
  • @Neil Kirk I never claimed such a thing. Where did you read that? – gifnoc-gkp Aug 01 '13 at 19:59
  • What thing are you refering to?? – Neil Kirk Aug 01 '13 at 20:01
  • @Neil Kirt What are you talking about? – gifnoc-gkp Aug 01 '13 at 20:03