5

Possible Duplicate:
Are global variables bad?

I am writing a simulation code making use of material and energy specific data. This data is stored in global arrays, because once uploaded, they are used during the simulation and should be accessible by most of the functions.

I read everywhere that it is not good practice to use global variables. Could someone explain me or point me to material on the web explaining how I could avoid using global arrays in simulation application coding while massive data arrays need to be used. I try to code in C++ and make use as much as possible of object oriented features.

Thanks in advance for your help.

Community
  • 1
  • 1
noste99
  • 375
  • 3
  • 14
  • 3
    I don't think this is a duplicate. The OP is **not asking If & why Global variables are bad?** **The question how to avoid them in his/her specific scenario.** – Alok Save Jul 23 '11 at 11:04

5 Answers5

1

You are right about the fact that, using globals are not recommended. You can declare those unrelated golbals inside a namespace,

//Globals.h
namespace Globals
{
  extern int a[100];
  extern double d;
}

and define them in a .cpp file.

//Globals.cpp
int Globals::a[100] = { ... };
double Globals::d = 3.14;

Now use them as Globals::a, Globals::d etc. My answer is in code management perspective.

iammilind
  • 68,093
  • 33
  • 169
  • 336
  • I tried to put the dimension of array a in a predefined parameter MAX_NUM as #define MAX_NUM 100 and I did not worked with the namespace. I did not expected that the #define MAX_NUM needed to be placed in the Globals.h instead of in the Globals.cpp where it is used. Any good feason for this? – noste99 Jul 23 '11 at 13:25
  • `MAX_NUM` is a preprocessor which is evaluated before compilation starts. You should put that macro above wherever you use. So in your case you should put it in top of `Globals.h` – iammilind Jul 23 '11 at 13:33
1

Have a look at this article about global variables. This is an excerpt:

Why Global Variables Should Be Avoided When Unnecessary

Non-locality -- Source code is easiest to understand when the scope of its individual elements are limited. Global variables can be read or modified by any part of the program, making it difficult to remember or reason about every possible use.

No Access Control or Constraint Checking -- A global variable can be get or set by any part of the program, and any rules regarding its use can be easily broken or forgotten. (In other words, get/set accessors are generally preferable over direct data access, and this is even more so for global data.) By extension, the lack of access control greatly hinders achieving security in situations where you may wish to run untrusted code (such as working with 3rd party plugins).

Implicit coupling -- A program with many global variables often has tight couplings between some of those variables, and couplings between variables and functions. Grouping coupled items into cohesive units usually leads to better programs.

Concurrency issues -- if globals can be accessed by multiple threads of execution, synchronization is necessary (and too-often neglected). When dynamically linking modules with globals, the composed system might not be thread-safe even if the two independent modules tested in dozens of different contexts were safe.

Namespace pollution -- Global names are available everywhere. You may unknowingly end up using a global when you think you are using a local (by misspelling or forgetting to declare the local) or vice versa. Also, if you ever have to link together modules that have the same global variable names, if you are lucky, you will get linking errors. If you are unlucky, the linker will simply treat all uses of the same name as the same object.

Memory allocation issues -- Some environments have memory allocation schemes that make allocation of globals tricky. This is especially true in languages where "constructors" have side-effects other than allocation (because, in that case, you can express unsafe situations where two globals mutually depend on one another). Also, when dynamically linking modules, it can be unclear whether different libraries have their own instances of globals or whether the globals are shared.

Testing and Confinement - source that utilizes globals is somewhat more difficult to test because one cannot readily set up a 'clean' environment between runs. More generally, source that utilizes global services of any sort (e.g. reading and writing files or databases) that aren't explicitly provided to that source is difficult to test for the same reason. For communicating systems, the ability to test system invariants may require running more than one 'copy' of a system simultaneously, which is greatly hindered by any use of shared services - including global memory - that are not provided for sharing as part of the test.

It also discusses several alternatives. Possibly in your case, you could consider:

  1. hiding your globals (e.g., private static variables);

  2. stateful procedures: setter and getter functions allowing access to the arrays while also "masking" it;

  3. the singleton pattern.

EDIT:

I understand that a part of the development community are against the use of the singleton pattern. I fully respect this opinion. Anyway, in the context of the present discussion, the singleton offers several advantages over the raw use of globals:

  1. improved access control;

  2. opportunity for synchronization;

  3. ability to abstract away the implementation.

In this respect, it is not better from a setter/getter set of functions, but still, not worse. I leave to the OP the hard task of choosing what to do with his own code. (BTW, the article discusses more approaches, like Context Objects, DependencyInjection, etc).

Community
  • 1
  • 1
sergio
  • 68,819
  • 11
  • 102
  • 123
  • 1
    Getting rid of one beast to leave the OP fighting with another(Singleton!) is a bad idea. – Alok Save Jul 23 '11 at 11:06
  • 1
    @Als: The article that I link discusses clearly how well (or bad) the singleton pattern performs compared to other approaches. I fully respect any opinions about singletons, but the first thing to me is understanding why is bad (or good) and then responsibly choosing. Anyway, taking into account this critical stance, I added one more bit of info to my answer. – sergio Jul 23 '11 at 11:22
1

Introducing global state into your code can make it difficult to do things in a multi-threaded way.

I would also argue it can make the intent of your code more difficult to follow. If you pass all of the arguments to a function as parameters at least it's clear what data the function has access to, and what has the potential of changing. The use of global variables doesn't give someone reading the code this chance...

It's also not generally true that using global variables is in any way faster. If you have large objects that you need to pass to functions, pass these arguments via references and there won't be any issues with copying.

Without knowing more about your setup, it's difficult to make any recommendations, but if you have a large amount of data that needs to be passed around to a series of routines I would be tempted to put it all in a struct, and to pass that struct by reference:

struct my_data_type
{
    double some_data;
    double some_other_data;

    std::vector<double> some_coefficients;
    std::vector<double> some_other_coefficients;

    std::string some_name;
    std::string some_other_name;

    // add more members as necessary...
};

void foo(my_data_type &data)
{
    // there's no big overhead passing data by reference
}

If you only need to access the data in a read-only fashion, it's best to pass as a const reference:

void foo(my_data_type const&data)
{
    // again, efficient, but ensures that data can't be modified
}

EDIT: In answer to your comment, I'm not talking about a "global" structure. You would need to declare a local struct variable, read the data from your file into the struct and then pass it by reference to any functions that need to be called:

int main()
{
    // a local struct to encapsulate the file data
    my_data_type file_data;

    // read the data from your file into file_data

    // the struct containing the data is passed by reference
    foo(file_data);

    return 0;
}
Darren Engwirda
  • 6,915
  • 4
  • 26
  • 42
  • I agree, but may be one clarification. The data I read from a csv file and store it in a global variable array that after reading should remain constant. The read parameters need to be used in a function. In fact it is not so much about global variables but about global constants. – noste99 Jul 23 '11 at 12:12
  • @noste: Typically, when people talk about "constants" they mean things that can be determined to be constant at *compile* time. Since your program reads the data at *runtime*, this data has to be stored in variables. You can mark it as "constant" by passing as `const&` - see my last point above. – Darren Engwirda Jul 23 '11 at 12:20
  • How much is this struct different from a global variable? It is accessible from everywhere in the code and the data is accessed by reference. The only difference is that one can make the data constant or not. I read somewhere as a solution a constant class, but I have no idea what it is. – noste99 Jul 23 '11 at 12:30
  • @noste: see my edit. The idea is *not* to use any global variables, but to use local variables, so that you can control their lifetimes and how they're accessed. – Darren Engwirda Jul 23 '11 at 13:02
  • Thanks a lot. I think this is the solution. I still find it a bit complicated compared to a global array. Every record I read from the csv file contains an integer value (index), a string (mnemonic) and a varying number of double precission coefficients to be completed with again a strig containing a comment. In the struct I could, may be, combine the different types data and pass them as one item to functions. Is that the added value? – noste99 Jul 23 '11 at 13:18
  • @noste: You can put whatever you want in the structure. If you're dealing with variable length arrays you might want to consider using `std::vector` containers. – Darren Engwirda Jul 23 '11 at 13:33
1

Yes you are right, global variables are not good. This is a useful link which explains why global variables are bad and how to avoid them.

http://c2.com/cgi/wiki?GlobalVariablesAreBad

EDIT: @sergio's post also points to the same link, you can ignore this answer

A. K.
  • 34,395
  • 15
  • 52
  • 89
1

Could someone explain me or point me to material on the web explaining how I could avoid using global arrays in simulation application coding while massive data arrays need to be used.

The same way you avoid globals in general: by using locals instead. The natural way to get data into a function is to pass it as a parameter. This is not expensive, especially if you pass by reference where appropriate.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153