views:

1516

answers:

8

Let's consider a C++ class. At the beginning of the execution I want to read a set of values from an XML file and assign them to 7 of the data members of this class. Those values do not change during the whole execution and they have to be shared by all the objects / instances of the class in question. Are static data members the most elegant way to achieve this behavior? (Of course, I do not consider global variables)

Thanks,

Diego.

+1  A: 

Sounds like a good use of static variables to me. You're using these more as fixed parameters than variables, and the values legitimately need to be shared.

David Thornley
+1  A: 

static members would work here and are perfectly acceptable. Another option is to use a singleton pattern for the class that holds these members to ensure that they are constructed/set only once.

Rob Prouse
+3  A: 

As others have mentioned, the use of static members in this case seems appropriate. Just remember that it is not foolproof; some of the issues with global data apply to static members:

  • You cannot control the order of initialization of your static members, so you need to make sure that no globals or other statics refer to these objects. See this C++ FAQ Question for more details and also for some tips for avoiding this problem.
  • If your accessing these in a multi-threaded environment you need to make sure that the members are fully initialized before you spawn any threads.
zdan
The values are being set at the start of execution, so those issues aren't really applicable here.
David Thornley
David, they will once you decide to put an xml object as a static object somewhere. also order of destruction is relevant too. see my answer below.
Johannes Schaub - litb
+1  A: 

sounds like an appropriate use of static class members. just don't forget that they're really global variables with a namespace and (maybe) some protection. therefore, if there's the possibility that your application could someday evolve separate 'environments' or something that would need a set of these globals for each, you'd have painted yourself into a corner.

as suggested by Rob, consider using a singleton, which is easier to turn later into some kind of managed environment variable.

Javier
+1  A: 

It is not a clean design. Static class members are global state and global state is bad.

It might not cause you trouble if this is a small- to medium-sized project and you do not have high goals for automatic testing, but since you ask: there are better ways.

A cleaner design would be to create a Factory for the class and have the Factory pass your seven variables to the class when it constructs it. It is then the Factory's responsility to ensure that all instances share the same values.

That way your class becomes testable and you have properly separated your concerns.

PS. Don't use singletons either.

Rasmus Faber
Any time that I read "xxx is bad", my oversimplification detector starts flashing. Like other posters, I believe that this use of static variables is perfectly valid.
Jon Trauntvein
Global state is primarily bad if it changes. Unchanging global state, which this is, works just fine.
David Thornley
Just read your link; it says that Singletons (and the roughly equivalent global state) don't harm anything if they contain immutable data, which this is.
David Thornley
It very well might be. But Diego asked: "Are static data members the most elegant way to achieve this behavior?", and using global state is surely not elegant. It works, and it might not actually cause you any problems - but it is not elegant.
Rasmus Faber
@David: It is not immutable if it is read from an XML file. It might not change at runtime, but that is not the kind of immutability that Misko talks about in his article.
Rasmus Faber
I agree with Rasmus. The state is *not* immutable because the static members can be changed at any time, there is no guarantee they won't be changed during the execution of the program from another source. This will cause the behavior of every instance to change.
Kamil Kisiel
A: 

As long as you think of testability and you have another way to set the static variables besides reading in a file, plus you don't rely on the data benig unchanged for the entire execution time of the process - you should be fine.

I've found that thinking of writing tests when you design your code helps you keep the code well-factored and reusable.

Arkadiy
A: 

Yes, static datamembers are what you look for. But you have to take care for the initialization/destruction order of your static variables. There is no mechanism in C++ to ensure that your static variables are initialized before you use them across translation units. To be safe, use what looks like the singleton pattern and is well known to fix that issue. It works because:

  1. All static objects are completely constructed after the complete construction of any xml_stuff instance.
  2. The order of destruction of static objects in C++ is the exact opposite of the completion of their construction (when their constructor finishes execution).

Code:

class xml_stuff {
public:
    xml_stuff() {
        // 1. touch all members once
        // => 2. they are created before used
        // => 3. they are created before the first xml_stuff instance
        // => 4. they will be destructed after the last xml_stuff instance is 
        //       destructed at program exit.
        get_member1();
        get_member2();
        get_member3();
        // ...
    }  

    // the first time their respective function is called, these
    // objects will be created and references to them are returned.
    static type1 & get_member1() { static type1 t; return t; }
    static type2 & get_member2() { static type2 t; return t; }
    static type1 & get_member3() { static type1 t; return t; }
    // ... all other 7 members
};

Now, the objects returned by xml_stuff::get_memberN() are valid the whole lifetime of any xml_stuff instance, because any of those members were constructed before any xml_stuff instance. Using plain static data members, you cannot ensure that, because order of creation across translation units is left undefined in C++.

Johannes Schaub - litb
+1  A: 

At the beginning of the execution I want to read a set of values from an XML file and assign them to 7 of the data members of this class. Those values do not change during the whole execution and they have to be shared by all the objects / instances of the class in question.

The sentence in boldface is the kicker here. As long as that statement holds, the use of static variables is OK. How will this be enforced?

It's hard to. So, if for your use right now the statement is always true, go ahead. If you want to be same from some future developer (or you) using your classes wrong (like reading another XML file midway in the program), then do something like what Rasmus Farber says.

moogs