3

I'm wondering about this. I've heard that global variables are bad, that they hurt the maintainability, usability, reusability, etc. of the code. But in this case, what can I do otherwise? Namely, I have a "pseudo-random number generator" (PRNG) and as one may know, they involve an internal state that changes every time new random numbers are generated. But this seems like the kind of thing that needs to be a global! Or a "static" member of an RNG class, but that's essentially a global! And globals are bad!

So, what can I do? The obvious thing is to have something like this (really stripped down):

class RNG {
      private:
          StateType state;              // this is the thing one may be tempted
                                        // to make "static", which ruins the
                                        // whole idea
      public:
          RNG();                        // constructor seeds the RNG
          ~RNG();
          int generateRandomInt();
};

But we need to seed that good, if we're going to create an instance of this every time we need a random number in some function or class. Using the clock may not work, since what if two instances of type "RNG" are created too close together? Then they get the same seed and produce the same random sequence. Bad.

We could also create one master RNG object and pass it around with pointers (instead of making it global, which would put us back on square 1), so that classes that need random numbers get a pointer to the RNG object in them. But then I run into a problem involving save/load of these objects to/from disk -- we can't just "save the RNG" for each instance, since we have only one RNG object. We'd have to instead pass an RNG into the load routines, which might give those routines different argument lists than for other objects that don't use the RNG. This would be a problem if, e.g. we wanted to use a common "Saveable" base class for everything that we can load/save. So, what to do? Eliminate the common "Saveable" base and just adopt a convention for how the load/save routines are to be made (but isn't that bad in and of itself? Oy!)?

What is the best solution to this that avoids the hostile-to-maintainability problems of globals yet also does not run into these new problems?

Or is it in fact okay to use a global here, as after all, that's how the "rand()" builtin works anyway? But then I hear that little thing in the back of my mind saying "but... but but but, globals are bad! Bad!" And from what I've read, there seem to be fairly good reasons to think them bad. But it seems like avoiding them creates new kinds of difficulties, like this one. It certainly seems harder to avoid globals than avoid "goto"s, for example.

jleahy
  • 16,149
  • 6
  • 47
  • 66
The_Sympathizer
  • 1,191
  • 9
  • 17
  • 4
    Not all global variables are bad. `std::cout` is one I'm particularly fond of. – Kerrek SB May 18 '12 at 21:47
  • It depends largely on what you're doing and your design. Both of them have obvious advantages and disadvantages. – Pubby May 18 '12 at 21:50

3 Answers3

4

There's some merit to your reluctance. You may want to substitute another generator for testing for example, that spits out a deterministic sequence that contains some edge cases.

Dependency Injection is one popular method for avoiding globals.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
1

A random number generator is one of those things that is more OK to be global. You can think of it as:

-A RandomNumberFactory, a design pattern that uses a global factory, and it builds random numbers for you. The factory is of course constant semantically (in C++ you might use the keyword "mutable" internally, if that means anything to you.)

-A global constant (global constants are ok, right?) that gives you read-only access to the global constant randomNumber. randomNumber just happens to be non-deterministic, but it's constant in that of course no application is going to write to it.

-And besides, what's the worst that could happen? In a multithreaded application your RNG will yield non-deterministic behavior? Gasp. As @Mark Ransom pointed out above, yes that is actually a drawback as it makes testing harder. If this is a concern to you, you might consider a design pattern that writes this out.

djechlin
  • 59,258
  • 35
  • 162
  • 290
0

It sometimes makes sense to use globals. No one can categorically say your code should not have any global variables, period.

What you do need is to be aware of the issues that can arise from global variables. If your application's logic needs global variables and it is possible for it to be called from a multi-threaded environment, then there is nothing inherently wrong with that, but you must take care to use locking, mutexes, and/or atomic reads/writes to ensure correct behavior.

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125