I'm working on compiling Cppcheck on AIX using xlC
. Every checker class is derived from a Check
class, whose constructor is responsible for registering that type of checker in a global static list.
Here's the relevant part of the code in question (filenames link to full source on Github):
check.h
class Check {
public:
Check() {
instances().push_back(this);
instances().sort();
}
static std::list<Check *> &instances() {
static std::list<Check *> _instances;
return _instances;
}
// ...
};
checkbufferoverrun.h
class CheckBufferOverrun: public Check {
// ...
};
checkbufferoverrun.cpp
// Register this check class (by creating a static instance of it)
namespace
{
CheckBufferOverrun instance;
}
Notice how the _instances
static variable is declared inside a static
function in the header file (there is no corresponding check.cpp
file). When compiled with g++
, the compiler and linker work together to ensure that there is only one implementation of the static instances()
function, and therefore only one instance of the static _instances
list. All the different checker classes instantiated in different .cpp
files get registered in the same _instances
list together.
However, under AIX's xlC
, this same code ends up creating a different instances()
function for every .cpp
file in which it is included, which each having a different static _instances
list. So there is no longer a single central _instances
list, which causes Cppcheck to not run most of its checks.
Which compiler's behaviour is correct in this case?
Update: This question is not about how to fix the problem, I've already done that. I'm curious about which behaviour is correct.
Correct it to:
If you inline the function in the header file, each compilation unit will initially compile its own definition. However at link-time they should be reduced to one instance because of the One-Definition Rule.
I am sure you are aware, of course, that your constructor to Check is not thread-safe. Your singleton constructor is also not totally thread-safe because although the ODR ensures the threads between them can only create one instance, the constructor of list is not atomic and therefore I am not sure it is guaranteed to be completely constructed before the other thread sees it.
For a totally thread-safe way of constructing singletons or non-atomic statics, you can use boost::once.
g++ has the correct behavior: there should be exactly one instance of the object. The C++ Standard says (C++03 7.1.2/4):
Because the class has external linkage, the static member function also has external linkage, per C++03 3.5/5:
Because the member function is defined in the class definition, it is an inline function, per C++03 7.1.2/3:
In this particular case g++ is correct (assuming that the
instances()
static member function returns a reference, that is a typo, right?). You might want to move the definition of theinstances()
function to a cpp file, that should be a work around in xlc.