C++, Static VS. Namespace VS. Singleton

C++, static vs. namespace vs. singleton

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!)

Singleton implementation: Is a namespace approach often preferable over a singleton class?

(I assume we can agree that global state is a dangerous thing that has to be used with special care.)

Technically your singleton namespace is equivalent to a singleton class. However it has one major drawback that makes it a no-go in my opinion: It hides the fact that it is stateful. Ever used std::strtok()? Remember what an atrocious mess it is? That’s because it hides its statefulness, too.

Because global state is inherently dangerous, any piece of functionality that uses it should make that fact abundantly clear at the call site, preferrably by using language constructs – because nobody reads comments or documentation. A Foo::instance()->do_work(); is a known pattern that makes it quite clear that something special is going on; a foo::do_work(); does not.

using namespaces instead of singletons

is this a good alternative to using global static variables, or a singleton?

no, because you might encounter another problem: static initialization order fiasco. There are ways to fix it - but with functions with static variables - which looks just like singletons.

... but why do you need a global variables (even in namespaces) or singletons? In you first example, it would be perfectly fine if instead of namespace ListA you had struct ListA - plus remove that namespace{. Then you have:

int main() {
ListA list;
list.init();
list.place("b1", new B("b1"));
list.place("a1", new A("a1"));
}

and it looks fine.

Then your singleton aproach, once again - no need for it - create variable of type EmployeeManager in your main function, if you need to use it in some other class, then pass it by reference or pointer.

Meyers Singleton : static keyword confusion

Is static keyword mentioned in the Line 1 meaningless ? If so why ?

It is not meaningless, if you need it or not depend on your situation. static in C++ means different thing in different context, in this case it makes this function only available on current compilation unit. Modern way to do it in C++ - to put the function into anonymous namespace.

What's the difference between a static member variable and a namespace variable?

Just in terms of the object you're declaring

The namespace declaration defines an object uniquely for the whole program. If you put that in a header file, including the header from two different source files would produce a multiple definition linker error.

The class static declaration asks the linker to share one object among all source files.

As for class vs. namespace

Classes and namespaces are completely different things. A class describes how to form an object. Class templates may also be used to form metaprograms. But a class should not be used merely to group things inside a scope, such that the class is never instantiated. That is the job of a namespace.

If you want to share the object among several sources, do this:

// Foo.h
namespace Foo {

extern int bar; // declaration

}

// Foo.cpp
namespace Foo {

int bar = 2; // definition

}

If the object is a constant, the definition is unnecessary as long as you never require bar to have an address in memory.

Difference between static class and singleton pattern?

What makes you say that either a singleton or a static method isn't thread-safe? Usually both should be implemented to be thread-safe.

The big difference between a singleton and a bunch of static methods is that singletons can implement interfaces (or derive from useful base classes, although that's less common, in my experience), so you can pass around the singleton as if it were "just another" implementation.

Namespaces vs. Static Classes

This line is particularly bad:

static library::Foo Foo;

It emits a static copy of Foo in every translation. Don't use it :) The result of Foo::some_value would be equal to the number of translations the Foo.h was visible to, and it's not thread safe (which will frustrate your users).

This line will result in multiple definitions when linking:

int Foo::some_value = 0;

Singletons are also bad. Searching here @SO will produce a lot of reasons to avoid them.

Just create normal objects, and document to your users why they should share objects when using your library, and in which scenarios.

User of the library doesn't need to worry about initialization. They wouldn't need to call something like Foo::init(); inside their main(), because library::Foo was initialized when my_project::Foo was constructed. This is the main design constraint here. User should not be responsible for initializing the library.

Objects should be able to construct themselves as needed without introducing unstrippable binary baggage.

I can create various private functions inside the library to control its use.

That's not unique to your approach.

The user can create other instances of this library if they choose, for whatever reason. But no copying would be allowed. One instance would be provided for them by default. This is a requirement.

Then you can force your users to pass Foo as a necessary argument to create the types they depend upon (where Foo is needed).

I can use the . syntax instead of ::. But that's a personal style thing.

Not good. Not threadsafe, and the user can then seriously mess up your library's state. Private data is best.



Related Topics



Leave a reply



Submit