c++ - Qt Singleton implementation -


i looking singleton qt implementation , found this. have question it.

  1. what purpose of making create qbasicatomicpointer ?
  2. what point in qcallonce of using testandsetrelaxed if have used fetchandstoreacquire ? isn't acquire semantic preventing memory reordering after ?
  3. what purpose of qcallonceperthread function ? isn't qcallonce thread-safe ?

i copy contents of 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 {         {             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 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 enough use next singleton implementation. remember, c++11 gurantees there 1 instancing/initialization static variable. original problem in case, when more 1 thread tries access instance in same time , there possible situation, when singleton created twice.

template <typename t, typename d = t> class singleton {     friend d;     static_assert(std::is_base_of_v<t, d>, "t should base type 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(); 

Comments

Popular posts from this blog

angular - Ionic slides - dynamically add slides before and after -

minify - Minimizing css files -

Add a dynamic header in angular 2 http provider -