6

What I want to do: run some prerequisite code whenever instance of the class is going to be used inside a program. This code will check for requiremts etc. and should be run only once.

I found that this can be achieved using another object as static variable inside a constructor. Here's an example for a better picture:

class Prerequisites
{
     public:
         Prerequisites() {
              std::cout << "checking requirements of C, ";
              std::cout << "registering C in dictionary, etc." << std::endl;
         }
};


class C
{
    public:
         C() {
             static Prerequisites prerequisites;
             std::cout << "normal initialization of C object" << std::endl;
         }
};

What bothers me is that I haven't seen similar use of static variables so far. Are there any drawbacks or side-effects or am I missing something? Or maybe there is a better solution? Any suggestions are welcome.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
mip
  • 8,355
  • 6
  • 53
  • 72
  • 1
    I think you should reconsider your design by instead taking whatever prereq as an argument to the constructor. It makes dependencies more clear for the user of your class. – AndersK May 29 '10 at 23:22
  • @Anders K: This isn't about a choice of class user but rather about testing runtime environment. To be more specific, I want for example to check for available OpenGL extensions, which C class will use. Whenever required extensions is not available, program will simply print error message and exit with failure. – mip May 29 '10 at 23:31
  • What I meant was a user (a programmer) using your class. It is more clear if the constructor needs to know the available opengl extensions then doing silently behind the scenes. – AndersK May 29 '10 at 23:37
  • @Anders K: I know what you mean, but it isn't the case. Class user (programmer) has no clue of what `C` class may need, since it is implementation detail. On the other hand C class knows what it will need, but because of OpenGL design, this can be checked only during runtime. – mip May 29 '10 at 23:50
  • Yes its clear that I would like show while you want like to hide, personally when I use other people's classes I like them rather light weight because they tend then to be more reusable but to each his own. – AndersK May 30 '10 at 01:10
  • @Anders K: It is not that I like to hide something. In my case, it would be just stupid to expose Prerequisites to class users. – mip May 30 '10 at 01:57

3 Answers3

7

This isn't thread-safe, since if two threads try to construct C for the first time at the same time, Prerequisites will probably be initialized twice.

If you're okay with that, you can probably do this, though gaming the scoped constructor system has zero discoverability (i.e. once you forget the 'trick' or others try to read your code, they'll be baffled as to what's going on).

Ana Betts
  • 73,868
  • 16
  • 141
  • 209
  • @doc Late here, but writing your code in a way that is at least _thread conscious_ (and not blatantly thread-apathetic) usually results in cleaner, faster, better, and more resilient code. – Qix - MONICA WAS MISTREATED Dec 14 '16 at 10:43
  • @doc Meaning don't write code that relies on running in a single threaded environment specifically - e.g. the "tricks" mentioned here. – Qix - MONICA WAS MISTREATED Dec 14 '16 at 22:15
  • @Qix why not? Single-threaded code is cleaner and less error prone in most cases. If you decide to gurantee thread-safety, then users of your code expect it to be trully thread-safe. This complicates things, because you have to deal with mutexes, locks, racing conditions, atomicity and there's more places, where you can make bugs (and when dealing with threads they can be very subtle and hard to debug). – mip Dec 14 '16 at 22:37
  • @doc I never said guaranteeing thread safety. I'm saying don't take shortcuts just because you assume it'll always be single threaded. I never said you needed to use mutexes and locks and whatnot. – Qix - MONICA WAS MISTREATED Dec 15 '16 at 08:16
  • @Qix What do you mean by "shortcuts"? The code presented in the question is a perfectly legal C++ code, so I don't know what is your concern. A piece of code can be designed to be thread-safe, reentrant or none of the above. You have to decide, which path is applicable for your code. If you decide that your code should be run from different threads, then you have to guarantee thread-safety and this often means use of mutexes, locks, atomics and complicates things, so normally you do it only if your code benefits from multi-threading. – mip Dec 15 '16 at 11:16
  • 1
    As a note, this should be thread-safe using any compliant C++11 compiler, due to how magic statics work. – Justin Time - Reinstate Monica Aug 15 '19 at 17:13
4

Are there any drawbacks or side-effects or am I missing something? Or maybe there is a better solution? Any suggestions are welcome.

It might be clearer (though more verbose) to explicitly invoke a static method.

class Prerequisites
{
    static bool checkedOnce;    
public:
    static void checkOnce() {
        if (checkedOnce)
        {
            //already checked: don't check again
            return;
        }
        //else check them now
        checkedOnce = true;
        std::cout << "checking requirements of C, ";
        std::cout << "registering C in dictionary, etc." << std::endl;
    }
};

bool Prerequisites::checkedOnce = false;

class C
{
public:
    C() {
        Prerequisites::checkOnce();
        std::cout << "normal initialization of C object" << std::endl;
    }
};
ChrisW
  • 54,973
  • 13
  • 116
  • 224
  • You're maybe right that this is clearer. But what about defining `checkedOnce` boolean as static inside checkOnce()? Less verbosity and still should be clear (?). + atomicity in C++0x. – mip Jun 04 '10 at 21:27
  • @doc -- I suggested this more verbose way because it's clearer/more explicit/uses less magic. Could you supply a citation/reference about atomicity of static local variables in C++0x? – ChrisW Jun 04 '10 at 22:21
  • I read that here on stackoverflow under following link http://stackoverflow.com/questions/898432/how-is-static-variable-initialization-implemented-by-the-compiler/898603#898603 – mip Jun 05 '10 at 00:24
1

You should at least use a mutex and a static flag inside Prerequisites class to protect agains multiple initialization of Prerequisites objects. In that way your code will become thread safe.

Jorg B Jorge
  • 1,109
  • 9
  • 17
  • Thread safety isn't a problem here but thanks for advice. BTW I heard that C++0x will make initialization of static variables thread-safe. – mip May 30 '10 at 00:13