On 8/12/2015 1:09 PM, Dan Kegel wrote: > On Wed, Aug 12, 2015 at 12:58 PM, Jeffrey Walton <noloa...@gmail.com> wrote: >> The C++ object that uses it is in another translation unit, and it has >> a init_pritority attribute. > File-scope or static C++ objects are the spawn of the devil. > There is no reliable or portable way to control initialization order, > even with init_priority, See e.g. > http://stackoverflow.com/questions/3371968/attribute-init-priorityx-in-gcc >
I got around this problem in C++ by defining an initialization order-independent method of creating global variables: /* nvalues.hpp */ class nv_base { public: nv_base(const my_string &name); const my_string &name(void) const { return _name; } ... private: my_string _name; static nv_base *first_nv; /* for hash table initialization */ nv_base *next_nv; /* traverse from first_nv */ nv_base(const nv_base &other); /* unimplemented */ nv_base &operator =(const nv_base &other); }; /* nvalues.cpp */ nv_base *nv_base::first_nv = 0; nv_base::nv_base(const my_string &name) { /* define a new named variable - must be global */ _name = name; next_nv = first_nv; /* link ourselves in */ first_nv = this; } class nv_integer : public nv_base { ... }; /* client.cpp */ nv_integer config_param("a_named_integer_value",5); As shown, client code derives from the base class, so I could have an integer value, a string value, etc. The traversal links allow high-level code to dump all of the values for debugging or saving state. There is a routine, invoked by main(), to prevent creation of these objects on the stack or with operator new (in my case, it also built a hash table for all the names). Access to the value in a named variable is only through a member function, so regardless of link order, when you access a variable it is initialized. Zero initialization is done before the program starts (ARM section 3.4), and global variables in a translation module are initialized before any code in that module (e.g. the constructors) is called. Originally I wrote this in 1991, for some of the very first C++ compilers. As features were added, I began to hit linkage order problems. I went to great lengths to make it link-order safe across platforms, compilers, and compiler versions, even defining a shadow set of utility routines for use only by this subsystem so there were no dependency loops. After all that, I used only one of these variables in 500,000 lines of code. Even though they were intended only for configuration parameters (the global list allowed me to dump the system configuration in the event of an error), I found that it was too difficult to isolate problems in code, or even to reuse it, when there was an arbitrary number of global variables influencing it. Now I refactor the code to avoid global variables, even if it means passing a value through multiple levels of existing code. I learned to pass a parameter block to a function as soon as the number of parameters got too high, or if I had to add a parameter to that function later. If I have to modify a function once, it's a safe bet that I will have to modify it again. It's much easier to add a field to a parameter block and define a good default value (in the constructor for C++ or the allocator function in C) than to modify every function call to have another argument. Also, I avoid default function parameter values in C++ because they make calling code harder to understand, and in a real product a function is called many more times than it is defined (i.e. once). Global variables are going to cause problems if you rely on the compiler, linker, or loader to initialize or destroy them in the order you want. Your code will always be vulnerable to the whims of another programmer. That programmer could be working on GCC, a run-time library, the OS, or even for you - when global variables change state at surprising times, every line of code in your program suddenly becomes a suspect. I've seen development of a suite of commercial products (millions of dollars per year in sales) be crippled by the use of global variables, even without considering initialization order. So even though I just told you how to guarantee that global variables in C++ are initialized before they are used, don't do it. :-) Refactoring sounds expensive but in the long run it is cheaper than debugging interactions between global variables. -- David Chapman dcchap...@acm.org Chapman Consulting -- San Jose, CA Software Development Done Right. www.chapman-consulting-sj.com ------------------------------------------------------------------------------ _______________________________________________ Valgrind-users mailing list Valgrind-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/valgrind-users