I recently was reading an article labeled "Modern C++ Singleton Template". The proposed solution used C++11 feature of Magic Statics (N2660). I wanted to adapt it for an own project in "freestanding" (fno-hosted) environment.
My code looks as follows:
Singleton.hpp
namespace std
{
template <typename T>
class Singleton
{
public:
// = initialization and termination methods
Singleton( const Singleton& ) = delete; // copy constructor
Singleton( Singleton&& ) = delete; // move constructor
Singleton& operator=( const Singleton& ) = delete; // assignment operator
Singleton& operator=( Singleton&&) = delete; // copy move operator
// = accessor methods.
static T& getInstance();
protected:
Singleton() {}; // default constructor
~Singleton() {}; // default destructor
struct Token {};
private:
}; // end template class T
template <typename T>
T& Singleton<T>::getInstance()
{
static T __singleInstance( Token{} );
return( __singleInstance );
} // end public method 'getInstance()'
} // end namespace std
Test.hpp
#include "libs/libc++/singleton.hpp" // declaration of template class 'Singleton'
class Test final : public TestSingelton<Test>
{
public:
Test(TestToken);
~Test();
void use();
};
Test.cpp
Test::Test(TestToken)
{
logTraceEvent_m( loging to file );
}
Test::~Test()
{
logTraceEvent_m( loging to file );
}
void
Test::use()
{
logTraceEvent_m( loging to file );
}
Problem
In hosted environment (Linux, GCC 7.5.0) it works as presented in the article refereed to above. The static variable is initialized only once; the constructor of the derived class is called only once.
Entering main()
Entering a()
constructed
in use
Entering b()
in use
Leaving main()
destructed
However, in my "-ffreestandig" environment it is not working. "freestanding" = kernel without any standard headers; without any libraries!
Static variable ("__singleInstance") is initialized on every call to "Test::getInstance()".
______ TRACE: constructor = Test::Test(TestSingelton<Test>::TestToken), ...
______ TRACE: use = void Test::use(), file = test/Test.cpp, line = 37.
______ TRACE: constructor = Test::Test(TestSingelton<Test>::TestToken), ...
______ TRACE: use = void Test::use(), file = test/Test.cpp, line = 37.
What I'm doing wrong? Is there any advice in which direction I have to investigate?
- compiler options?
- -W -Wall -pedantic -ffreestanding -std=gnu++17 -fno-PIC -fno-exceptions -fno-rtti -fno-use-cxa-atexit -march=native -m64 -mcmodel=kernel -mno-red-zone -mno-sse3 -mno-ssse3 -mno-sse4.1 -mno-sse4.2 -mno-sse4 -mno-sse4a -mno-3dnow -mno-avx -mno-avx2
- runtime environment, that is missing something