Avoid non-`const` global variables
Reason
Non-const global variables hide dependencies and make the dependencies subject to unpredictable changes.
Example
struct Data {
// ... lots of stuff ...
} data; // non-const data
void compute() // don't
{
// ... use data ...
}
void output() // don't
{
// ... use data ...
}
Who else might modify data?
Warning: The initialization of global objects is not totally ordered. If you use a global object initialize it with a constant. Note that it is possible to get undefined initialization order even for const objects.
Exception
A global object is often better than a singleton.
Note
Global constants are useful.
Note
The rule against global variables applies to namespace scope variables as well.
Alternative: If you use global (more generally namespace scope) data to avoid copying, consider passing the data as an object by reference to const. Another solution is to define the data as the state of some object and the operations as member functions.
Warning: Beware of data races: If one thread can access non-local data (or data passed by reference) while another thread executes the callee, we can have a data race. Every pointer or reference to mutable data is a potential data race.
Using global pointers or references to access and change non-const, and otherwise non-global, data isn't a better alternative to non-const global variables since that doesn't solve the issues of hidden dependencies or potential race conditions.
Note
You cannot have a race condition on immutable data.
References: See the rules for calling functions.
Note
The rule is "avoid", not "don't use." Of course there will be (rare) exceptions, such as cin, cout, and cerr.
Enforcement
(Simple) Report all non-const variables declared at namespace scope and global pointers/references to non-const data.