Tom Lachecki

(Tomalak Geret'kal)


Clang Breaks Template Rules, Confuses Me

A friend posed a question this evening as to why the following code should not be accepted as valid C++03:

This code is accepted by clang, but rejected by (at least) g++ 4.4-4.6 with the diagnostic:

error: no matching function for call to `fill(unsigned char*&, unsigned char*, Foo::<anonymous enum>)`

At first I blamed too many implicit conversion steps but, after a short discussion, the answer turned out to be quite simple: the enum is anonymous, and std::fill is a template whose third implicit argument here is an anonymous type… which is impossible in C++03.

If we pass the value as the int that it was always destined to become (before eventually becoming a char), we get:

Which behaves as one expects on all toolchains.

C++0x will accept anonymous types as template parameters but, for now, clang appears to be in error. At least it's filed. 🙂

Tags: , ,
Permalink | No Comments  
Tomalak's Tuesday Tip #8: Outsmarting Static Initialization

Right or wrong, it's still trendy in some C++ circles to use the singleton pattern for defining a type that can only be instantiated at most once in an execution run. An example might be a god class that manages the top-level of your framework:

The constructor is private, so nobody can outright just instantiate a Kernel instance; in the meantime, the Kernel::getInstance() function will give you access to the static member Kernel instance that's created once during static initialisation.

Problem

However, this can cause problems when you bring more static data into the mix. Consider the following example:

Because the Kernel instance is created before the Utility instance's constructor is invoked, this is safe.

But if we flip the static initialisation order of the two objects, then we're trying to use a data member inside Kernel that hasn't been initialised yet:

Worse, if your Utility and Kernel instances are defined in difference Translation Units (loosely corresponding to .cpp source files in most projects), then their order of initialisation is completely non-guaranteed. It's pot luck as to whether your "simple" code will function at all.

Solution

It may seem contrived but this pattern has been seen in production code. To get around this issue when one static object depends on another static object, you can instead rely on the create-on-demand semantics of function-statics (an altogether different feature of the language):

In fact, in general it's best to try to avoid relying on static data members as these sorts of errors can go unnoticed for some time, and exerting control over C++'s static initialisation order is the sort of magic trickery best left to gremlins and hyperdimensional beings.

Update 18/12/2010:

I'm having to add an addendum here to address a typical counter-response to my advice above.

It's been contested a few times that you can retain the use of the static member instance by using indirection, as in the following code. However, I've annotated the code to demonstrate how using dynamic allocation and a static member pointer does not solve this problem:

Remember: always prefer a function-static implementation object for singletons!

Tags: , , ,
Permalink | [3] Comments