3

in a C++ program I need some helper constant objects that would be instantiated once, preferably when the program starts. Those objects would mostly be used within the same translation unit, so the simplest way to do this would be to make them static:

static const Helper h(params);

But then there is this static initialization order problem, so if Helper refers to some other statics (via params), this might lead to UB.

Another point is that I might eventually need to share this object between several units. If I just leave it static and put in a .h file, that would lead to multiple objects. I could avoid that by bothering with extern etc, but this can finally provoke the same initialization order issues (and not to say it looks very C-ish).

I thought about singletons, but that would be overkill due to the boilerplate code and inconvenient syntax (e.g. MySingleton::GetInstance().MyVar) - those objects are helpers, so they are supposed to simplify things, not to complicate them...

The same C++ FAQ mentions this option:

 Fred& x()
 {
   static Fred* ans = new Fred();
   return *ans;
 } 

Is this really used and considered a good thing? Should I do it this way, or would you suggest other alternatives? Thanks.

EDIT: I should have clarified why I actually need that helpers: they are very like normal constants, and could have been pre-calculated, but it is more convenient to do that at runtime. I would prefer to instantiate them before main, as it automatically resolves multi-threading issues (which local statics are not protected against in C++03). Also, as I said, they would often be limited to a translation unit, so it does not make sense to export them and initialize in main(). You can think of them as just constants but only known at runtime.

Roman L
  • 3,006
  • 25
  • 37
  • If it weren't considered a good thing, it wouldn't be in the FAQ! So if you want to use that idiom, go ahead. – Philipp Jan 28 '11 at 15:11
  • @Philipp: global state is never a good thing... @7vies: there is no reason to allocate `ans` on the heap, unless you wish to leak somehow. – Matthieu M. Jan 28 '11 at 15:31
  • 1
    @Philipp: as far as I see, it is not a collaborative FAQ, and I don't have a reason to completely rely on the author's opinion – Roman L Jan 28 '11 at 15:32
  • What makes you think it should not be considered a good thing? – wich Jan 28 '11 at 15:32
  • @Matthieu: Well, the reason for dynamic allocation is nicely explained in the FAQ, as well as the "leak" issue. – Roman L Jan 28 '11 at 15:36
  • @wich: Nothing. Well, there is this "leak" issue that might bother some people and tools... But I'm simply asking if it is a good way to go or there are better options. – Roman L Jan 28 '11 at 15:40
  • @7vies, what leak issue? – wich Jan 28 '11 at 15:41
  • @wich: As I already said, it's explained in the FAQ: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.16 But again, I don't care about this, my question is if there are other options. – Roman L Jan 28 '11 at 15:45
  • 1) there is no leak, it gets cleaned up on program termination anyway, 2) if you want to satisfy tools or your concience register an exithandler with atexit that destroys the objects in the proper order, but why on earth would you. – wich Jan 28 '11 at 15:50
  • Using a singleton can be simplified with #define HELPER MySingleton::GetInstance() so you need only use HELPER.myVar. – badgerr Jan 28 '11 at 15:51
  • @wich: 1) I know that. But as I said, some tools and people are still not happy with that. 2) This becomes too complicated for a helper :( – Roman L Jan 28 '11 at 15:51
  • @7vies, sorry hit enter too early, see my revised comment – wich Jan 28 '11 at 15:52
  • @wich: okay, I've revised my comment too – Roman L Jan 28 '11 at 15:54
  • @wich: there is a leak. It get cleans up on process termination, but if you use dll_open / dll_close facilities... and re-open the library several times... then it leaks. Note that it's taken care of using `atexit` I think... – Matthieu M. Jan 28 '11 at 15:58
  • @7vies: I know that the fact mention leaking as an alternative because of the Destruction Order Fiasco. But do note that leaking implies that the destructor will never get called even though the memory will be reclaimed in the end. – Matthieu M. Jan 28 '11 at 16:00
  • @7vies, Why is runtime initialization preferred? Is it that you want to keep the calculation in the code and in a structured way? If so perhaps template meta-programming may let you calculate the constants at compile time while still keeping the calculation in the code in a structured way. – wich Jan 28 '11 at 17:07
  • @Matthieu, exit handler execution on dl_close is a non-portable affair. – wich Jan 28 '11 at 17:10
  • @wich: It's about strings, I guess it's even impossible to do templates on them. Also, runtime calculations are often way more straightforward to write and debug than magic template code, so I believe that templates are not always the best option. – Roman L Jan 28 '11 at 17:13
  • @7vies: exotic solution --> having a script generate the constants. Generated code is not so bad as long as the script itself is portable. – Matthieu M. Jan 28 '11 at 17:56
  • @Matthieu: Yep, I thought of code generation too - could be an option, but it adds a dependency on the tool and is limited as the tool does not have the C++ type system. So I always try to consider all prons and cons... – Roman L Jan 28 '11 at 18:15

4 Answers4

5

There are several possibilities for global state (whether mutable or not).

If you fear that you'll have an initialization issue, then you should use the local static approach to create your instance.

Note that the clunky singleton design you present is not mandatory design:

class Singleton
{
public:
  static void DoSomething(int i)
  {
    Singleton& s = Instance();
    // do something with i
  }


private:
  Singleton() {}
  ~Singleton() {}

  static Singleton& Instance()
  {
    static Singleton S; // no dynamic allocation, it's unnecessary
    return S;
  }
};

// Invocation
Singleton::DoSomething(i);

Another design is somewhat similar, though I much prefer it because it makes transition to a non-global design much easier.

class Monoid
{
public:
  Monoid()
  {
    static State S;
    state = &s;
  }

  void doSomething(int i)
  {
    state->count += i;
  }

private:
  struct State
  {
    int count;
  };

  State* state;
};


// Use
Monoid m;
m.doSomething(1);

The net advantage here is that the "global-ness" of the state is hidden, it's an implementation details that clients need not worry about. Very useful for caches.

Let us, will you, question the design:

  • do you actually need to enforce the singularity ?
  • do you actually need the object be built before main starts ?

Singularity is generally over-emphasized. C++0x will help here, but even then, technically enforcing singularity rather than relying on programmers to behave themselves can be very annoying... for example when writing tests: do you really want to unload/reload your program between each unit test just to change the configuration between each one ? Ugh. Much more simple to instantiate it once and have faith in your fellow programmers... or the functional tests ;)

The second question is more technical, than functional. If you do need the configuration before the entry point of your program, then you can simply read it when it starts.

It may sound naive, but there is actually one issue with computing during the library load: how do you handle errors ? If you throw, the library is not loaded. If you do not throw and go on, you are in an invalid state. Not so funny, is it ? Things are much simpler once the real work has begun, because you can use the regular control-flow logic.

And if you think about testing whether the state is valid or not... why not simply building everything at the point where you'd test ?

Finally, the very issue with global is the hidden dependencies that are introduced. It's much better when dependencies are implicit to reason about the flow of execution, or the impacts of a refactoring.


EDIT:

Regarding initialization order issues: objects within a single translation unit are guaranteed to be initialized in the order they are defined.

Therefore, the following code is valid according to the standard:

static int foo() { return std::numeric_limits<int>::max() / 2; }
static int bar(int c) { return c*2; }

static int const x = foo();
static int const y = bar(x);

The initialization order is only an issue when referencing constants / variables defined in another translation unit. As such, static objects can naturally be expressed without issues as long as they only refer to static objects within the same translation unit.

Regarding the space issue: the as-if rule can do wonders here. Informally the as-if rule means that you specify a behavior and leave it up to the compiler/linker/runtime to provide it, without a care in the world for how it is provided. This is what actually enables optimizations.

Therefore, if the compiler chain can infer that the address of a constant is never taken, it may elide the constant altogether. If it can infer that several constants will always be equal, and once again that their address are never inspected, it may merge them together.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • Thanks for such detailed answer! The monoid trick is indeed interesting. Though, singletons aren't probably a good option in my case, as they require to write all this boilerplate code, while what I need is very much just a constant (I've updated the question with more details, please take a look). So in most cases I won't need a global access. Singularity is not absolutely required either, but it would be more optimal to not duplicate my constants into each translation unit (they consume memory). Lazy objects are also an option, but then I need to workaround multi-threading issues. – Roman L Jan 28 '11 at 16:26
  • @Matthieu: error handling is a good point too, I'll have to think about this. – Roman L Jan 28 '11 at 16:38
  • @7vies: in C++0x, local static are guaranteed to be initialized once even in the presence of multi-threading. In general, gcc (and Clang I think) already behaved so, even though the standard made no such guarantee. – Matthieu M. Jan 28 '11 at 16:47
  • @Matthieu: For me it's no luck: C++03 and VS. – Roman L Jan 28 '11 at 16:50
  • @7vies: I had a nagging doubt that you already replied so to another remark of mine :) Check Visual Studio's documentation though, it may also offer this guarantee. And I updated my answer :) – Matthieu M. Jan 28 '11 at 16:55
  • @Matthieu: It is very possible that I did :) Concerning your edit, that's a good point too - I should probably just forget about single instance, as it simplifies everything. However, my constants are actually classes. Imagine that such class has a static member - and here we go again with the static gotchas... Well, probably the answer to this is just "don't do that", but if there existed something else than statics, it could resolve all issues for me, without hidden restrictions. That led to my question :) – Roman L Jan 28 '11 at 17:07
  • @7vies: if the constant is a class, then you can use a local static for the internal static member and just declare static instances of the class normally. – Matthieu M. Jan 28 '11 at 17:54
  • @Matthieu: Yes, but there is a restriction "if you did that, then do that" which is *hidden* (not checked by the compiler) - I try to avoid such things as much as possible. – Roman L Jan 28 '11 at 18:18
2

Yes, you can use Construct On First Use Idiom if it simplifies your problem. It's always better than global objects whose initialization depend on other global objects.

The other alternative is Singleton Pattern. Both can solve similar problem. But you've to decide which suits the situation better and fulfill your requirement.

To the best of my knowledge, there is nothing "better" than these two appproaches.

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • This could be an answer... if it added something to what I've already said :\ Or should I consider it as "there is nothing else, use one of these two"? – Roman L Jan 28 '11 at 15:34
  • @7vies: To the best of my knowledge, there is nothing "better" than these two. – Nawaz Jan 28 '11 at 15:40
  • @Nawaz: Ok, but this comment looks like a better answer to me than your answer :) – Roman L Jan 28 '11 at 15:50
  • Construct on first use is not "always better". It introduces overhead to test for construction. If you're certain the objects will be required this overhead serves no useful purpose. – Jay Jan 28 '11 at 19:32
  • @Jay: Your comment makes no sense to me. Which "overhead to test" are you talking about? – Nawaz Jan 28 '11 at 19:34
0

Singletons and global objects are often considered evil. The simplest and most flexible way is to instantiate the object in your main function and pass this object to other functions:

void doSomething(const Helper& h);
int main() {
  const Parameters params(...);
  const Helper h(params);
  doSomething(h);
}

Another way is to make the helper functions non-members. Maybe they don't need any state at all, and if they do, you can pass a stateful object when you call them.

I think nothing speaks against the local static idiom mentioned in the FAQ. It is simple and should be thread-safe, and if the object isn't mutable, it should also be easily mockable and introduce no action at a distance.

Philipp
  • 48,066
  • 12
  • 84
  • 109
  • They are considered evil because of the global **mutable** state. I'm talking about immutable objects. Again, passing helpers as parameters would complicate things, not simplify them. – Roman L Jan 28 '11 at 15:05
  • 3
    There is nothing evil about globals and sigletons. You just need to know how dynamic initialization works and how to enforce its order. In any application there are things that must exist in one instance and be globally accessible. – Maxim Egorushkin Jan 28 '11 at 15:06
  • 1
    @Maxim: There are already *a lot* of discussions on this, let's please don't start that once again :) Mutable global state *is* considered evil, due to the side effects etc etc, but that's a completely different discussion! – Roman L Jan 28 '11 at 15:08
  • @7vies: I just wanted to let you know that global state is not generally considered evil, there are just two different schools of thought... – Maxim Egorushkin Jan 28 '11 at 15:19
  • @7vies - having dependencies on global objects increases coupling and hurts testability, even if the value of the global objects never changes. – JoeG Jan 28 '11 at 16:20
  • @Joe: That's a choice to make between "perfect" and simple code. Singletons don't increase coupling with respect to passing-through-constructor, as the dependency is always there, singletons just hide it (which is not a good thing, though). In any case, such discussions tend to be very vague, I've already seen many of them and wouldn't like to start a new one... – Roman L Jan 28 '11 at 16:36
0

Does Helper need to exist before main runs? If not, make a (set of?) global pointer variables initialized to 0. Then use main to populate them with the constant state in a definitive order. If you like you can even make helper functions that do the dereference for you.

Mark B
  • 95,107
  • 10
  • 109
  • 188