Home > Software design >  C : static member of template singleton class doesn't get compiled/linked
C : static member of template singleton class doesn't get compiled/linked

Time:09-26

I implemented a singleton class in c using double checked lock(with safe locks), it works. Then I try to convert it into template version, like this:

// singleton.h
#include <atomic>
#include <mutex>
template<typename T>
struct singleton {
    ~singleton() {}
    static singleton<T>* getInstance(std::mutex& m);
    static std::atomic<singleton<T>*> m_instance; // this is the problem.
};

template<typename T>
singleton<T> * singleton<T>::getInstance(std::mutex& m) {
    auto temp = m_instance.load(std::memory_order_acquire);
    if (temp == nullptr) {
        std::lock_guard<std::mutex> lock(m);
        temp = m_instance.load(std::memory_order_relaxed);
        if (temp == nullptr) {
            temp = new singleton();
            m_instance.store(temp, std::memory_order_release);
        }
    }
    return temp;
}

Then in a .cpp file I wish to use this class. Note the storage of static std::atomic<singleton<T>*> m_instance needs to exist in my .cpp file, so I tried this:

struct M {
    int m_i;
    static std::mutex m;
};

std::atomic<singleton<M>*> singleton<M>::m_instance; // error:

nullity) {
    auto instance1 = singleton<M>::getInstance(M::m);
    auto instance2 = singleton<M>::getInstance(M::m);
}

The line of m_instance definition reports:

template specialization requires 'template<>'
std::atomic<singleton<M>*> singleton<M>::m_instance;

How to fix this syntax error? Thanks.

CodePudding user response:

Don't try to explicitly specialize the static data member, just define it for the primary template itself (in the header file):

template<typename T>
std::atomic<singleton<T>*> singleton<T>::m_instance{nullptr};

Alternatively mark m_instance in the class template definition as inline (since C 17) and add the {nullptr} initialization there. (Beware that you must initialize explicitly to nullptr. The default constructor of std::atomic does not perform proper initialization before C 20.)

There is no need to add anything in the source file.


The whole thing is extremely redundant though, since the compiler will add the whole locking mechanism to dynamic initialization of a local static storage duration variable anyway (since C 11). You don't need to do anything manually. The common approach is to define the singleton as

static auto& getInstance() {
    static singleton<T> instance;
    return instance;
}

without a static data member, or if the dynamic storage duration is important to you

static auto& getInstance() {
    static auto instance = std::make_unique<singleton<T>>();
    return *instance;
}
  • Related