I'm implementing a Singleton template in C++. I try to achieve thread-safe by std::call_once and std::once_flag, but somehow link error happens.
singleton.h
#ifndef _SINGLETON_H_
#define _SINGLETON_H_
#include <boost/noncopyable.hpp>
#include <mutex>
template<typename T>
class Singleton : boost::noncopyable {
public:
Singleton() = delete;
static T& getInstance() {
std::call_once(init_flag_, &Singleton::init);
return *val_;
}
private:
static void init() {
val_ = new T();
}
private:
static std::once_flag init_flag_;
static T* val_;
};
#endif // _SINGLETON_H_
test_singleton.cc
#include "singleton.h"
#include <iostream>
class Log {
public:
void log() {
std::cout << "log" << std::endl;
}
};
int main() {
Log & logger = Singleton<Log>::getInstance();
logger.log();
}
And my g++ statement is
g++ -std=c++14 -pthread -o test test_singleton.cc
Error message:
/tmp/ccoxQBXl.o: In function `Singleton<Log>::getInstance()':
test_singleton.cc:(.text._ZN9SingletonI3LogE11getInstanceEv[_ZN9SingletonI3LogE11getInstanceEv]+0x2c): undefined reference to `Singleton<Log>::init_flag_'
test_singleton.cc:(.text._ZN9SingletonI3LogE11getInstanceEv[_ZN9SingletonI3LogE11getInstanceEv]+0x38): undefined reference to `Singleton<Log>::val_'
/tmp/ccoxQBXl.o: In function `Singleton<Log>::init()':
test_singleton.cc:(.text._ZN9SingletonI3LogE4initEv[_ZN9SingletonI3LogE4initEv]+0x11): undefined reference to `Singleton<Log>::val_'
collect2: error: ld returned 1 exit status
Finally got it. The only problem is I didn't initialize the static variables.
For C++17, inline keyword allows initialization within class.
#ifndef SINGLETON_H_
#define SINGLETON_H_
#include <boost/noncopyable.hpp>
#include <mutex>
template<typename T>
class Singleton : boost::noncopyable {
public:
Singleton() = delete;
static T& getInstance() {
std::call_once(init_flag_, &Singleton::init);
return *val_;
}
private:
static void init() {
val_ = new T();
}
private:
static inline std::once_flag init_flag_{};
static inline T* val_ = nullptr;
};
#endif // SINGLETON_H_
Related
There is an issue with my Instance class in that I noticed a difference in behavior that stems from two methods of initializing a static member.
The class template Instance is keeping track of a unique count. The unique count is being used to keep track of the amount of derived classes for a specific type. It is also used to assign a unique id/index for derived classes.
The first is initialized as follows:
template<typename Derived, typename Key>
Key Instance<Derived, Key>::count_static_assign{ std::numeric_limits<Key>::min() };
The second is initialized as such:
template<typename Derived, typename Key>
Key Instance<Derived, Key>::count_default{ 0 };
Program's output
1 1
2 1
I expect the two values to be equal because they should both be incrementing. However count_static_assign, is giving the wrong output as it appears to reset and be equal to 1 twice. Thus, I would like to know why there is a difference in behavior between these two static variables.
Here are the files for the program that demonstrates the error.
Instance.h
#ifndef INSTANCE_H
#define INSTANCE_H
#include <cinttypes>
#include <limits>
#include <iostream>
template<typename Derived, typename Key = std::uint16_t>
class Instance {
public:
using KeyType = Key;
static KeyType count_static_assign;
static KeyType count_default;
public:
Instance() = default;
virtual ~Instance() = default;
virtual KeyType getInstance() const = 0;
protected:
static KeyType generate() {
count_static_assign++;
count_default++;
std::cout << count_default << ' ' << count_static_assign << '\n';
return count_default;
}
};
//doesn't behave as expected
template<typename Derived, typename Key>
Key Instance<Derived, Key>::count_static_assign{ std::numeric_limits<Key>::min() };
//behaves as expected
template<typename Derived, typename Key>
Key Instance<Derived, Key>::count_default{ 0 };
#endif
Base.h
#ifndef BASE_H
#define BASE_H
#include <cinttypes>
#include <typeindex>
#include <memory>
#include "Instance.h"
class Base : public Instance<Base>
{
public:
Base(){}
~Base(){}
};
template<typename Derived>
class CRTPBase : public Base {
public:
static const KeyType STATIC_TYPE;
CRTPBase() {}
virtual ~CRTPBase() {}
virtual KeyType getInstance() const override {
return STATIC_TYPE;
}
};
template<typename Derived>
const typename CRTPBase<Derived>::KeyType CRTPBase<Derived>::STATIC_TYPE = CRTPBase<Derived>::generate();
#endif
Foo.h
#ifndef FOO_H
#define FOO_H
#include "Base.h"
struct Foo : public CRTPBase<Foo> {
Foo();
~Foo();
};
#endif
Foo.cpp
#include "Foo.h"
Foo::Foo()
{
}
Foo::~Foo()
{
}
Bar.h
#ifndef BAR_H
#define BAR_H
#include "Base.h"
struct Bar : public CRTPBase<Bar>
{
public:
Bar();
~Bar();
};
#endif
Bar.cpp
#include "Bar.h"
Bar::Bar()
{
}
Bar::~Bar()
{
}
main.cpp
#include "Foo.h"
#include "Bar.h"
int main() {
Foo foo;
Bar bar;
std::cin.get();
}
If it matters, I am using Visual Studio 2017(Full Version-191426433) to compile. In addition, debug and release mode make no difference.
This code looks correct to me: count_default and count_static_assign have constant expressions as initializers, so they must be initialized before any dynamic initialization happens. STATIC_TYPE is dynamic initialization.
OP reports that changing std::numeric_limits<Key>::min() to 0 fixes the behaviour of the program, so I would conjecture that the compiler has a bug that it does not consider the constexpr function std::numeric_limits<Key>::min() to be a constant expression.
To work around this you could try some other way of coming up with a constant initializer for count_static_assign, e.g. a constexpr function that you write yourself, or a specialization for each type that you do use.
I'm new to template programming. While implementing singleton class using template, I found in some cases (as below shows) the linker complains error:
undefined reference to `Singleton<Test>::_lock'
However, if I change following statement
template<> Mutex Singleton<Test>::_lock;
to
template<> Mutex Singleton<Test>::_lock(1);
it compiles and runs without error.
Could someone helps me out and explains why in below case the compiling fails?
#include <iostream>
#include <pthread.h>
class Mutex {
public:
Mutex(){ pthread_mutex_init(&mMutex, NULL); }
Mutex(int dummy){ pthread_mutex_init(&mMutex, NULL); }
~Mutex(){ pthread_mutex_destroy(&mMutex); }
Mutex(const Mutex&) = delete;
Mutex& operator = (const Mutex&) = delete;
int lock(){ return -pthread_mutex_lock(&mMutex); }
void unlock(){ pthread_mutex_unlock(&mMutex); }
// Manages the mutex automatically. It'll be locked when Autolock is
// constructed and released when Autolock goes out of scope.
class Autolock {
public:
explicit Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }
~Autolock() { mLock.unlock(); }
private:
Mutex& mLock;
};
private:
pthread_mutex_t mMutex;
};
template <typename T>
class Singleton: {
public:
static T& Instance() {
Mutex::Autolock _l(_lock);
if(nullptr == _instance) {
_instance = new T();
}
return *_instance;
}
virtual ~Singleton(){}
Singleton() = default;
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
static T* _instance;
static Mutex _lock;
};
class Test: public Singleton<Test> {
public:
void dis() {std::cout << "hi" << std::endl;}
};
template<> Mutex Singleton<Test>::_lock;
template<> Test* Singleton<Test>::_instance(nullptr);
template class Singleton<Test>;
int main()
{
Test::Instance().dis();
return 0;
}
I was looking for a Singleton Qt implementation and found this. but I have some question about it.
What is the purpose of making create a QBasicAtomicPointer ?
What is the point in qCallOnce of using testAndSetRelaxed if previously we have used fetchAndStoreAcquire ? Isn't the acquire semantic already preventing any memory reordering after it ?
What is the purpose of the qCallOncePerThread function ? Isn't qCallOnce already thread-safe ?
I copy the contents of the suggested implementation here:
call_once.h
#ifndef CALL_ONCE_H
#define CALL_ONCE_H
#include <QtGlobal>
#include <QAtomicInt>
#include <QMutex>
#include <QWaitCondition>
#include <QThreadStorage>
#include <QThread>
namespace CallOnce {
enum ECallOnce {
CO_Request,
CO_InProgress,
CO_Finished
};
Q_GLOBAL_STATIC(QThreadStorage<QAtomicInt*>, once_flag)
}
template <class Function>
inline static void qCallOnce(Function func, QBasicAtomicInt& flag)
{
using namespace CallOnce;
#if QT_VERSION < 0x050000
int protectFlag = flag.fetchAndStoreAcquire(flag);
#elif QT_VERSION >= 0x050000
int protectFlag = flag.fetchAndStoreAcquire(flag.load());
#endif
if (protectFlag == CO_Finished)
return;
if (protectFlag == CO_Request && flag.testAndSetRelaxed(protectFlag,
CO_InProgress)) {
func();
flag.fetchAndStoreRelease(CO_Finished);
}
else {
do {
QThread::yieldCurrentThread();
}
while (!flag.testAndSetAcquire(CO_Finished, CO_Finished));
}
}
template <class Function>
inline static void qCallOncePerThread(Function func)
{
using namespace CallOnce;
if (!once_flag()->hasLocalData()) {
once_flag()->setLocalData(new QAtomicInt(CO_Request));
qCallOnce(func, *once_flag()->localData());
}
}
#endif // CALL_ONCE_H
singleton.h
#ifndef SINGLETON_H
#define SINGLETON_H
#include <QtGlobal>
#include <QScopedPointer>
#include "call_once.h"
template <class T>
class Singleton
{
private:
typedef T* (*CreateInstanceFunction)();
public:
static T* instance(CreateInstanceFunction create);
private:
static void init();
Singleton();
~Singleton();
Q_DISABLE_COPY(Singleton)
static QBasicAtomicPointer<void> create;
static QBasicAtomicInt flag;
static QBasicAtomicPointer<void> tptr;
bool inited;
};
template <class T>
T* Singleton<T>::instance(CreateInstanceFunction create)
{
Singleton::create.store(create);
qCallOnce(init, flag);
return (T*)tptr.load();
}
template <class T>
void Singleton<T>::init()
{
static Singleton singleton;
if (singleton.inited) {
CreateInstanceFunction createFunction = (CreateInstanceFunction)Singleton::create.load();
tptr.store(createFunction());
}
}
template <class T>
Singleton<T>::Singleton() {
inited = true;
};
template <class T>
Singleton<T>::~Singleton() {
T* createdTptr = (T*)tptr.fetchAndStoreOrdered(nullptr);
if (createdTptr) {
delete createdTptr;
}
create.store(nullptr);
}
template<class T> QBasicAtomicPointer<void> Singleton<T>::create = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
template<class T> QBasicAtomicInt Singleton<T>::flag = Q_BASIC_ATOMIC_INITIALIZER(CallOnce::CO_Request);
template<class T> QBasicAtomicPointer<void> Singleton<T>::tptr = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
#endif // SINGLETON_H
How to use
// myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
class MyClass : public QObject
{
Q_OBJECT
private:
MyClass(QObject* parent = 0);
static MyClass* createInstance();
public:
~MyClass();
static MyClass* instance();
};
#endif // MYCLASS_H
// myclass.cpp
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
#include "singleton.h"
MyClass::MyClass(QObject* parent):
QObject(parent)
{
}
MyClass* MyClass::createInstance()
{
return new MyClass();
}
MyClass::~MyClass()
{
}
MyClass* MyClass::instance()
{
return Singleton<MyClass>::instance(MyClass::createInstance);
}
#endif // MYCLASS_H
main.cpp
#include <QTextStream>
#include "myclass.h"
#define MyClassInstance Singleton<MyClass>::instance()
int main(int argc, char* argv[])
{
QTextStream(stdout) << MyClass::instance()->metaObject()->className() << endl;
return 0;
}
I think that is will be enough to use next singleton implementation. As I remember, C++11 gurantees that there will be only one instancing/initialization for a static variable.
Original problem was in case, when more than one thread tries to access an instance in same time and there were possible a situation, when singleton was created twice.
template <typename T, typename D = T>
class Singleton
{
friend D;
static_assert(std::is_base_of_v<T, D>, "T should be a base type for D");
public:
static T& instance();
private:
Singleton() = default;
~Singleton() = default;
Singleton( const Singleton& ) = delete;
Singleton& operator=( const Singleton& ) = delete;
};
template <typename T, typename D>
T& Singleton<T, D>::instance()
{
static D inst;
return inst;
}
// Usage:
class MyClass : public Singleton<MyClass>
{
public:
void foo(){}
};
// Access:
MyClass::instance().foo();
Main concept of using Singleton pattern is to restrict the instantiation to certain number of objects, in common use to one.
Q1 : Atomic pointer
Atomic operations are done without interruption , so handled multi-thread instance calls.
Q2 : point of qCallOnce
This function checks if any other threads are executing and if so wait for CO_finished flag in
do {
QThread::yieldCurrentThread();
}
while (!flag.testAndSetAcquire(CO_Finished, CO_Finished));
Q3 : point of qCallOncePerThread
if (!once_flag()->hasLocalData()) {
once_flag()->setLocalData(new QAtomicInt(CO_Request));
I think to handle LocalData of singleton class per each thread instacnes
I am new to C++ and trying to understand the Singleton Pattern in C++.
myclass.h
#ifndef MYCLASS_H
#define MYCLASS_H
class Myclass {
public:
static Myclass* getInstance();
private:
Myclass(){}
Myclass(Myclass const&){}
Myclass& operator=(Myclass const&){}
static Myclass* m_instance;
};
#endif // MYCLASS_H
myclass.cpp
#include "myclass.h"
Myclass* Myclass::getInstance() {
if (!m_instance) {
m_instance = new Myclass;
}
return m_instance;
}
The compiler can't compile. I get the following error, on all 3 lines with m_instance:
error: undefined reference to `Myclass::m_instance'
You forgot to add:
Myclass* Myclass::m_instance = 0; // or NULL, or nullptr in c++11
right under #include "myclass.h".
I have defined below hierarchy of classes, my intention is to design a generic class that allows me to iterate over enum objects (C++11 is not allowed to be used unfortunately). The class definition and test program are:
// base.h
#include <set>
template <typename T>
class Base
{
protected:
explicit Base(int value);
typedef typename std::set< Base<T>* > instances;
static instances s_instances;
int value_;
public:
int get_value() const { return value_ ; }
};
template <typename T>
Base<T>::Base(int value): value_(value)
{
s_instances.insert(this);
}
// derived.h
#include "base.h"
class Derived : public Base<Derived>
{
protected:
explicit Derived(int value): Base<Derived>(value) { }
public:
static const Derived value1;
};
// test.cc
#include "derived.h"
template<>
Base<Derived>::instances Base<Derived>::s_instances;
const Derived Derived::value1(1);
int main(int argc, char *argv[])
{
using std::cout;
using std::endl;
cout << Derived::value1.get_value() << endl;
}
On compilation using g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3, it gives me below linking error:
"
g++ test.cc -o test
/tmp/ccOdkcya.o: In function `Base<Derived>::Base(int)':
test.cc:(.text._ZN4BaseI7DerivedEC2Ei[_ZN4BaseI7DerivedEC5Ei]+0x28): undefined reference to `Base<Derived>::s_instances'
collect2: ld returned 1 exit status
"
Can anyone please suggest what am I missing in above code?
Thanks!
Static data members are declared in class definitions and defined outside the class definition. Like this:
// header:
class C {
static int i;
};
// source:
int C::i = 17;
With a template, you typically don't put any code in source files, so the definition goes in the header:
// header:
template <class T>
class C {
static int i;
};
template <class T>
int C<T>::i = 17;
Be aware that s_instances might not have been initialized before it is used.
You can only write
// template<> -> you should not write this in this case.
Base<Derived>::instances Base<Derived>::s_instances;
If you have provided an explicit specialization of Base<Derived>, such as :
class Derived;
template <>
class Base<Derived>
{
protected:
explicit Base(int value);
typedef typename std::set< Base<Derived>* > instances;
static instances s_instances;
int value_;
public:
int get_value() const { return value_ ; }
};
Otherwise, you have to stick to writing:
template<typename T>
typename Base<T>::instances Base<T>::s_instances;