C++, static vs. namespace vs. singleton

12,823

Solution 1

As noted, using global variables is generally bad engineering practice, unless absolutely needed of course (mapping hardware for example, but that doesn't happen THAT often).

Stashing everything in a class is something you would do in a Java-like language, but in C++ you don't have to, and in fact using namespaces here is a superior alternative, if only:

  • because people won't suddenly build instances of your objects: to what end ?
  • because no introspection information (RTTI) is generated for namespaces

Here is a typical implementation:

// foo.h
#ifndef MYPROJECT_FOO_H_INCLUDED
#define MYPROJECT_FOO_H_INCLUDED

namespace myproject {
  void foo();
  void foomore();
}

#endif // MYPROJECT_FOO_H_INCLUDED

// foo.cpp
#include "myproject/foo.h"

namespace myproject {

namespace {
  typedef XXXX MyHelperType;

  void bar(MyHelperType& helper);
} // anonymous

void foo() {
  MyHelperType helper = /**/;
  bar(helper);
}

void foomore() {
  MyHelperType helper = /**/;
  bar(helper);
  bar(helper);
}
} // myproject

The anonymous namespace neatly tucked in a source file is an enhanced private section: not only the client cannot use what's inside, but he does not even see it at all (since it's in the source file) and thus do not depend on it (which has definite ABI and compile-time advantages!)

Solution 2

Don't make it a singleton

For public helper functions that don't directly depend on these variables, make them non-member functions. There's nothing gained by putting them in a class.

For the rest, put it in a class as normal non-static members. If you need a single globally accessible instance of the class, then create one (but don't make it a singleton, just a global).

Otherwise, instantiate it when needed.

Solution 3

From your description it looks like you have methods and data that interact with each other here, in other words it sounds to me like you actually want a non-singleton class to maintain the state and offer operations upon that state. Expose your public functions as the interface and keep everything else private.

Then you can create instance(s) as needed, you don't have to worry about init order or threading issues (if you have one per thread), and only clients that need access will have an object to operate upon. If you really need just one of these for the entire program you could get away say a global pointer that's set in main or possibly an instance method, but those come with their own sets of problems.

Solution 4

What about using a keyword static at global scope (making stuff local to the file) as a privacy substitute?

Share:
12,823
blubberbernd
Author by

blubberbernd

Hi!

Updated on June 17, 2022

Comments

  • blubberbernd
    blubberbernd almost 2 years

    I already read a lot of posts and articles all over the net, but I couldn't find a definite answer about this.

    I have some functions with similar purposes that I want to have out of the global scope. Some of them need to be public, others should be private (because they are only helper functions for the "public" ones). Additionally, I don't have only functions, but also variables. They are only needed by the "private" helper functions and should be private, too.

    Now there are the three ways:

    • making a class with everything being static (contra: potential "Cannot call member function without object" - not everything needs to be static)
    • making a singleton class (contra: I WILL need the object)
    • making a namespace (no private keyword - why should I put it in a namespace at all, then?)

    What would be the way to take for me? Possible way of combining some of these ways?

    I thought of something like:

    1. making a singleton, the static functions use the helper function of the singleton object (is this possible? I'm still within the class, but accessing an object of it's type)
    2. constructor called at programm start, initializes everything (-> making sure the statics can access the functions from the singleton object)
    3. access the public functions only through MyClass::PublicStaticFunction()

    Thanks.

  • josesuero
    josesuero about 13 years
    Yay, anonymous downvotes. Anyone care to explain why this is a bad answer?
  • Emile Cormier
    Emile Cormier about 13 years
    I'm not the downvoter, but I'm guessing some might take issue with your "globally accessible instance" paragraph. Global objects suffer the same disadvantages as singletons (as singletons are merely global objects in disguise).
  • Emile Cormier
    Emile Cormier about 13 years
    Another point of contention might be "There's nothing gained by putting them in a class." There is one thing gained, albeit trivial: the class that holds the static member functions serves as a namespace. I realize that the same effect can be accomplished by namespace, but perhaps people coming from a Java background don't.
  • josesuero
    josesuero about 13 years
    @Emile: no they don't. Read the blog post I linked to. Singletons combine two different problems. A plain old global has only one of them. That's still enough to make it a bad solution most of the time, but I'd say a global has a few legitimate uses. A singleton has none.
  • josesuero
    josesuero about 13 years
    On your second point, as you say, a namespace is better for that purpose.
  • Emile Cormier
    Emile Cormier about 13 years
    @jalf: Just read your article. Very well written -- I like your prose. When I said "the same disadvantages as singletons", I guess I meant the global state disadvantage. The problems with singletons weren't so neatly categorized in my head.
  • blubberbernd
    blubberbernd about 13 years
    Thanks. I decided this as the best solution for my problem. I'm coming from C# (where everything is a class), that's why these (unnamed) namespace solutions are new to me.
  • Matthieu M.
    Matthieu M. about 13 years
    @blubberbernd: in this case I can only recommend a good C++ book. C++ is both rich and full of (bad) surprises, and a good tutorial can only help. There is a list on SO: stackoverflow.com/questions/388242/…
  • Rev
    Rev almost 8 years
    Nice answer. I am doing some embedded programming in C++ and was confronted with the problem that some peripherals just can be used (should be initialized) once. It was a natural thing to implement in C but I felt I HAD TO go for an object oriented approach using C++. But using a singleton was of limited use because I also had to implement related interrupt service routines as "free functions".
  • Rev
    Rev almost 8 years
    One question about the anonymous namespace: If the "private" functions aren't declared in the header, wouldn't that be enough to prevent client code from using them? Am I missing something?
  • Matthieu M.
    Matthieu M. almost 8 years
    @Rev1.0: Anonymous namespaces and static are there for linkage, primarily: the symbol is then not visible outside the translation unit in which it is defined, which avoids collisions. It also hints to the compiler that it need not emit the function code at all and might want to consider more strongly inlining it. Incidentally, it also prevents someone who has peeked into the source code from declaring the function so as to use it too: to use it they need to somehow inspect the binary to find its address... if it exists at all (ie, was not inlined).
  • Rev
    Rev almost 8 years
    Thanks for the feedback. So its effectively just a C++ alternative to the "static" you would use in C to restrict linkage to the module? Isn't using the "static" keyword a cleaner approach since it better conveys the intent?
  • Rev
    Rev almost 8 years
    I think I found the answer regarding static vs namespace myself: stackoverflow.com/a/4726710/1790864
  • Matthieu M.
    Matthieu M. almost 8 years
    @Rev1.0: the main advantage of unnamed namespace is that you can declare all kinds of things in there (such as new structs, etc...), in this case their auto-generated methods (constructors, ...) also get private linkage. Once you get used to using unnamed namespaces for "local" struct/class you also naturally use them for what could be static. There are further subtleties (wrt. specialization/name look-up) as well...
  • Escape0707
    Escape0707 about 3 years
    I wonder if this instead of a lazy initialized singleton will require the developer to manually handle lazy initialization using some flags like checking isInitialized or nullptr? If lazy init is required, is singleton a more suitable design?
  • Escape0707
    Escape0707 about 3 years
    Edit: never mind, just wrap the init in a referencing function.