Search code examples
c++global-variablesrandomstatic-variables

Can I use global variable instead of static local variable here?


The variable "initialized" in the method initRandomSeed()

/*
 * File: random.cpp
 * ----------------
 * This file implements the random.h interface.
 */


#include <cstdlib>
#include <cmath>
#include <ctime>
#include "random.h"
#include "private/randompatch.h"
using namespace std;

/* Private function prototype */

static void initRandomSeed();

/*
 * Implementation notes: randomInteger
 * -----------------------------------
 * The code for randomInteger produces the number in four steps:
 *
 * 1. Generate a random real number d in the range [0 .. 1).
 * 2. Scale the number to the range [0 .. N) where N is the number of values.
 * 3. Translate the number so that the range starts at the appropriate value.
 * 4. Convert the result to the next lower integer.
 *
 * The implementation is complicated by the fact that both the expression
 *
 *     RAND_MAX + 1
 *
 * and the expression for the number of values
 *
 *     high - low + 1
 *
 * can overflow the integer range.  These calculations must therefore be
 * performed using doubles instead of ints.
 */

int randomInteger(int low, int high) {
   initRandomSeed();
   double d = rand() / (double(RAND_MAX) + 1);
   double s = d * (double(high) - low + 1);
   return int(floor(low + s));
}

/*
 * Implementation notes: randomReal
 * --------------------------------
 * The code for randomReal is similar to that for randomInteger,
 * without the final conversion step.
 */

double randomReal(double low, double high) {
   initRandomSeed();
   double d = rand() / (double(RAND_MAX) + 1);
   double s = d * (high - low);
   return low + s;
}

/*
 * Implementation notes: randomChance
 * ----------------------------------
 * The code for randomChance calls randomReal(0, 1) and then checks
 * whether the result is less than the requested probability.
 */

bool randomChance(double p) {
   initRandomSeed();
   return randomReal(0, 1) < p;
}

/*
 * Implementation notes: setRandomSeed
 * -----------------------------------
 * The setRandomSeed function simply forwards its argument to srand.
 * The call to initRandomSeed is required to set the initialized flag.
 */

void setRandomSeed(int seed) {
   initRandomSeed();
   srand(seed);
}

/*
 * Implementation notes: initRandomSeed
 * ------------------------------------
 * The initRandomSeed function declares a static variable that keeps track
 * of whether the seed has been initialized.  The first time initRandomSeed
 * is called, initialized is false, so the seed is set to the current time.
 */

static void initRandomSeed() {
   static bool initialized = false;
   if (!initialized) {
      srand(int(time(NULL)));
      initialized = true;
   }
}

To ensure that the initialization code doesn’t get executed every time, you need a Boolean flag to record whether that initialization has been performed. Unfortunately, it doesn’t work to declare that flag as a global variable because C++ does not specify the order in which global variables are initialized. If you declare other global values whose initial values were produced by the random library, there would be no way to ensure that the initialization flag had been set correctly.

Can you give an example of "If you declare other global values whose initial values were produced by the random library, there would be no way to ensure that the initialization flag had been set correctly."


Solution

  • You want to search for Static initialization fiasco: https://cryptopp.com/wiki/Static_Initialization_Order_Fiasco

    For example, if you were to declare a global variable myInt:

    int myInt=initRandomSeed();

    this would get executed before your program enters the main() block, and there is no guarantee that initialized gets set up before myInt