Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. About Singleton Instances in Qt
Forum Updated to NodeBB v4.3 + New Features

About Singleton Instances in Qt

Scheduled Pinned Locked Moved C++ Gurus
8 Posts 5 Posters 18.9k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    subin
    wrote on last edited by
    #1

    Hi All,

    I've gone through a very good learning exresice last week - the singleton classes. I used it for handling a db instance so that I can use my db anywhere from my program without reinitializing the db. So far my singleton pattern works fine. Take a look at my class skeleton.

    @#ifndef DBHANDLER_H
    #define DBHANDLER_H
    #include <QtSql>

    class DbHandler {
    private:
    DbHandler();
    DbHandler(const DbHandler&);
    DbHandler& operator=(const DbHandler&);
    static bool instance;
    static DbHandler _dbH;
    QSqlDatabase db;
    public:
    static DbHandler
    getInstance();
    ~DbHandler();
    void readAllData();
    };
    #endif@

    My concerns about this declaration are.

    • Is it thread safe?
    • Is there any simple way apart from doing all this manually?

    I simply understand it is not thread safe. I use a boolean varibale named instance to make sure there exists an instance or not. So another thread can possibly change it. I have gone through the singleton design pattern in Wiki and have seen Java supports "thread safe singleton pattern":http://en.wikipedia.org/wiki/Singleton_pattern#Lazy_initialization. My first question is, does Qt support this? QMutex may be?
    Again Java supports far simpler declaration named the "enum way":http://en.wikipedia.org/wiki/Singleton_pattern#The_Enum_way. Does Qt have something similar? Feel free to point out if my assumptions are wrong.

    Thanks and Regards

    1 Reply Last reply
    0
    • J Offline
      J Offline
      joonhwan
      wrote on last edited by
      #2

      IMHO, singleton should be avoided as much as possible. That said, I believe you can use QMutex to check if '_dbH' instance is allocated or not in a threadsafe way.
      And you also can check Q_GLOBAL_STATIC() macro which can be used for singleto'nize a class' instance easily which is used inside Qt library(though it is not documented, it uses lock-free instance checking routine that is more efficient than using QMutex, i believe)

      joonhwan at gmail dot com

      1 Reply Last reply
      0
      • A Offline
        A Offline
        andre
        wrote on last edited by
        #3

        Singleton his its uses, but it also has its pitfals. Threading is one such pitfal.

        In your implementation, there are some issues:

        Why is delete public? Do you really want the users of your API to call:
        @
        delete DbHandler::getInstance();
        @
        That would result in a crash the next time you try to access the instance.

        Also, a Singleton should disable copying of the object, otherwise you can still get more than one instance of the class:
        @
        DbHandler theCopy(*(DbHandler::getInstance())); // just copied a singleton!
        @

        On the other hand: who is responsible for deleting the instance? One way would be to use a smart pointer instead of the raw pointer. The idea of using a bool too, I don't get.

        As you already noticed, there are threading issues. You can jump through fancy hoops to avoid this issue, but the simplest way to avoid issues is just to make sure that before you start your new threads, you initialize the object. You don't really need lazy instantiation for objects that you are sure to use anyway, right? However, do note that that basically reduces your singleton to a glorified global variable.

        1 Reply Last reply
        0
        • L Offline
          L Offline
          lgeyer
          wrote on last edited by
          #4

          A few annotations:

          • the boolean variable instance can be omitted, as the DbHandler pointer to the instance itself can be used to distinct between an initialized (dbH != 0) and a non-initialized (dbH == 0) singleton.
          • C++ does support both patterns you've mentioned, thread-safe and lazy-initialized.
            @
            class ThreadSafeSingleton
            {
            public:
            static ThreadSafeSingleton* instance() { return _instance; }

          private:
          ThreadSafeSingleton() {}
          static ThreadSafeSingleton* _instance;
          };

          ThreadSafeSingleton* ThreadSafeSingleton::_instance = new ThreadSafeSingleton;

          class LazySingleton
          {
          public:
          static LazySingleton* instance()
          {
          if(_instance == 0)
          _instance = new LazySingleton;

              return _instance;
          }
          

          private:
          LazySingleton() {}
          static LazySingleton* _instance;
          };

          LazySingleton* LazySingleton::_instance = 0;
          @
          If the lazy initialized singleton is used in multithreaded applications, instance() has to be made thread-safe (for example using QMutex). To partially negate its cost "double checked locking":http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf might be used. Alternatively Q_GLOBAL_STATIC() can be used, which is thread-safe as well.

          • Make sure you've understand the consequences when using a lazy-initialized singleton, especially when used with database connections. Typically a database-driven application establishes the connection to the database on startup once and fails when it isn't able to do so, which is contradictory to the principle of a (lazy-initialized) singleton.
          • Make sure you've have another good read on the downsides of singletons in C++, for example undefined construction order, destruction problems or slowed-down startup time.

          I agree with joonhwan and Andre that singletons should be avoided. I would even go a step further and would consider them as a classical anti-pattern which should be avoided whenever possible. There is a very good "Tech Talk":http://www.youtube.com/watch?v=-FRm3VPhseI with Miško Hevery explaining most of the issues.

          Fortunately Qt requires a comfortable way of having globally accessible data without using singletons: dynamic properties of the application object.
          @
          class DbHandler
          {
          // non-singleton, non-thread-safe implementation
          // of the database connection and access code
          ...
          };
          Q_DECLARE_METATYPE(DbHandler*);

          int main(int argc, char* argv[])
          {
          QApplication application(argc, argv);

          // create an instance of the database in main, where you can
          // do proper error handling and no thread-safety is required
          
          DbHandler* dbHandler = new DbHandler;
          
          // Make your DbHandler* globally accessible by settings it as a
          // dynamic property of the application object.
          
          application.setProperty("dbHandler", QVariant::fromValue<DbHandler*>(dbHandler));
          
          ....
          

          }

          void SomeObject::someMethod()
          {
          DbHandler* dbHandler = qApp->property("dbHandler").value<DbHandler*>();
          }
          @

          1 Reply Last reply
          0
          • G Offline
            G Offline
            goetz
            wrote on last edited by
            #5

            Ahm, am I missing something, or do you wrap a singleton class ([[Doc:QSqlDatabase]]) into a new singleton class? Is that for real code or only for learning purpose?

            http://www.catb.org/~esr/faqs/smart-questions.html

            1 Reply Last reply
            0
            • A Offline
              A Offline
              andre
              wrote on last edited by
              #6

              While QSqlDatabase has static methods to get or create instances, it does not qualify as a singleton IMO. It does instance management, but it does not limit you to only one instance.

              1 Reply Last reply
              0
              • G Offline
                G Offline
                goetz
                wrote on last edited by
                #7

                Ok, sort-of singleton :-)

                But it serves the purpose very well. You get the same database handle everytime you call the static methods. And of course one will need multiple instances if connections to multiple databases are needed.

                But one usually creates a handle, sets it up and opens the connection on applicatin startup. Afterwards one gets the handle via the static method. From a user's point of view, this behaves much like a singleton.

                http://www.catb.org/~esr/faqs/smart-questions.html

                1 Reply Last reply
                0
                • S Offline
                  S Offline
                  subin
                  wrote on last edited by
                  #8

                  Thank you all for your valuable feedbacks.

                  1 Reply Last reply
                  0

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved