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. To singleton or not to singleton, that is the question....
QtWS25 Last Chance

To singleton or not to singleton, that is the question....

Scheduled Pinned Locked Moved Solved C++ Gurus
23 Posts 4 Posters 2.3k Views
  • 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.
  • J JonB
    7 Nov 2024, 09:46

    @SimonSchroeder
    Yep, all good, a few comments from me.

    For the global stuff, @jsulm made a good point when he said "What you should avoid are global class instances/objects". I agree global functions are not so harmful.

    Does it make any sense to write Math.sqrt(x); in Java? Or is it better if you can write sqrt(x);? I prefer the latter.

    I think many years of C# programming in the past makes me think of everything having to be the former not the latter. There are no "free functions", everything must be in some class. Maybe same as Java, I don't know. And of course it's actually std::sqrt unless you are using std.

    With namespaces everything inside the header is public and everything that can only be found in the .cpp file is private. Using an unnamed namespace or marking free functions static just hides them during link-time as well

    Ah, this is good! I was thinking I had to declare all my functions inside the namespace in the header header as I would have to do for class but everything being public without any private keyword. To test I tried writing void RandomNumber::foo() { } in the .cpp (nothing in the .h) but that gives me ... should have been declared inside ‘RandomNumber’. To achieve a .cpp-only function I found I had to use the "alternative" syntax of:

    namespace RandomNumber
    {
    void foo() {}
    }
    

    or I could "add to" the namespace first in the .cpp and use:

    // top of file
    namespace RandomNumber
    {
        void RandomNumber::foo();
    }
    ...
    // later on
    void RandomNumber::foo() {}
    

    As an aside, this is just what I wish most that C++ had for classes. One of the things I hate most is that you have to put all your method declarations in the header file. I loathe having to put the private ones there, and consequently as well having to put in whatever #includes into the .h just to support anything in private. If classes could have their privates in the .cpp only as per the second way above it would be so much better, but I know you can't have "partial" classes in C++ which you can augment e.g. in the .cpp.

    workaround would be to use a function int &getMyVar() { static int myVar; return myVar; }

    Yes, that is what my original singleton pattern code used for its static RandomNumber& instance() method.

    @SimonSchroeder said in To singleton or not to singleton, that is the question....:

    Yes, in this case a singleton is the suboptimal solution. There are other cases where they make more sense.

    Agreed. I have changed all my stuff for this case to namespace, I have learned a lot about them so I am confident now going forward. I will worry about "other cases", perhaps when what I need really is a class for some reason, as and when I encounter them.

    J Online
    J Online
    jsulm
    Lifetime Qt Champion
    wrote on 7 Nov 2024, 09:51 last edited by
    #14

    @JonB said in To singleton or not to singleton, that is the question....:

    should have been declared inside ‘RandomNumber’

    This should work (in .cpp):

    void someHelperFunction()
    {
    }
    
    namespace RandomNumber
    {
        void foo()
        {
            someHelperFunction();
        }
    }
    

    https://forum.qt.io/topic/113070/qt-code-of-conduct

    J 1 Reply Last reply 7 Nov 2024, 09:57
    0
    • J JonB
      7 Nov 2024, 09:46

      @SimonSchroeder
      Yep, all good, a few comments from me.

      For the global stuff, @jsulm made a good point when he said "What you should avoid are global class instances/objects". I agree global functions are not so harmful.

      Does it make any sense to write Math.sqrt(x); in Java? Or is it better if you can write sqrt(x);? I prefer the latter.

      I think many years of C# programming in the past makes me think of everything having to be the former not the latter. There are no "free functions", everything must be in some class. Maybe same as Java, I don't know. And of course it's actually std::sqrt unless you are using std.

      With namespaces everything inside the header is public and everything that can only be found in the .cpp file is private. Using an unnamed namespace or marking free functions static just hides them during link-time as well

      Ah, this is good! I was thinking I had to declare all my functions inside the namespace in the header header as I would have to do for class but everything being public without any private keyword. To test I tried writing void RandomNumber::foo() { } in the .cpp (nothing in the .h) but that gives me ... should have been declared inside ‘RandomNumber’. To achieve a .cpp-only function I found I had to use the "alternative" syntax of:

      namespace RandomNumber
      {
      void foo() {}
      }
      

      or I could "add to" the namespace first in the .cpp and use:

      // top of file
      namespace RandomNumber
      {
          void RandomNumber::foo();
      }
      ...
      // later on
      void RandomNumber::foo() {}
      

      As an aside, this is just what I wish most that C++ had for classes. One of the things I hate most is that you have to put all your method declarations in the header file. I loathe having to put the private ones there, and consequently as well having to put in whatever #includes into the .h just to support anything in private. If classes could have their privates in the .cpp only as per the second way above it would be so much better, but I know you can't have "partial" classes in C++ which you can augment e.g. in the .cpp.

      workaround would be to use a function int &getMyVar() { static int myVar; return myVar; }

      Yes, that is what my original singleton pattern code used for its static RandomNumber& instance() method.

      @SimonSchroeder said in To singleton or not to singleton, that is the question....:

      Yes, in this case a singleton is the suboptimal solution. There are other cases where they make more sense.

      Agreed. I have changed all my stuff for this case to namespace, I have learned a lot about them so I am confident now going forward. I will worry about "other cases", perhaps when what I need really is a class for some reason, as and when I encounter them.

      J Online
      J Online
      jsulm
      Lifetime Qt Champion
      wrote on 7 Nov 2024, 09:53 last edited by
      #15

      @JonB said in To singleton or not to singleton, that is the question....:

      consequently as well having to put in whatever #includes into the .h just to support anything in private

      In case of pointers you can avoid the includes by using forward declarations.

      Often d pointer pattern is used to hide implementation details and keep binary compatibility while changing internal implementation.

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      J 1 Reply Last reply 7 Nov 2024, 10:02
      0
      • J jsulm
        7 Nov 2024, 09:51

        @JonB said in To singleton or not to singleton, that is the question....:

        should have been declared inside ‘RandomNumber’

        This should work (in .cpp):

        void someHelperFunction()
        {
        }
        
        namespace RandomNumber
        {
            void foo()
            {
                someHelperFunction();
            }
        }
        
        J Offline
        J Offline
        JonB
        wrote on 7 Nov 2024, 09:57 last edited by JonB 11 Jul 2024, 09:57
        #16

        @jsulm
        Hi, not sure if you are adding something here? I wrote above that, with nothing in the .h file, you can indeed put in the .cpp

        namespace RandomNumber
        {
            void foo() { ... }
        }
        

        What I said I found you cannot do is

        void RandomNumber::foo() { ... }
        

        For that, if you are not going to put

        namespace RandomNumber
        {
            void foo();
        }
        

        in the .h (because you want to only use it privately) then I found you can/must add it in the .cpp --- this adding to the namespace declarations from the .h --- before defining it via void RandomNumber::foo() { ... }.

        [I never had a question about some global/free someHelperFunction() function.]

        S 1 Reply Last reply 8 Nov 2024, 07:50
        0
        • J jsulm
          7 Nov 2024, 09:53

          @JonB said in To singleton or not to singleton, that is the question....:

          consequently as well having to put in whatever #includes into the .h just to support anything in private

          In case of pointers you can avoid the includes by using forward declarations.

          Often d pointer pattern is used to hide implementation details and keep binary compatibility while changing internal implementation.

          J Offline
          J Offline
          JonB
          wrote on 7 Nov 2024, 10:02 last edited by JonB 11 Jul 2024, 10:03
          #17

          @jsulm said in To singleton or not to singleton, that is the question....:

          In case of pointers you can avoid the includes by using forward declarations.

          Of course, and I do sometimes do that to avoid being forced to pull in a full #include. But when, say, you have a whole load of private methods in a class and they use types (copy or reference) as parameters/returns which are either from your own "internal" types or from external types you get forced to have the full #includes in the .h even if only relevant to your private methods. I hate that.

          1 Reply Last reply
          0
          • J JonB
            7 Nov 2024, 09:57

            @jsulm
            Hi, not sure if you are adding something here? I wrote above that, with nothing in the .h file, you can indeed put in the .cpp

            namespace RandomNumber
            {
                void foo() { ... }
            }
            

            What I said I found you cannot do is

            void RandomNumber::foo() { ... }
            

            For that, if you are not going to put

            namespace RandomNumber
            {
                void foo();
            }
            

            in the .h (because you want to only use it privately) then I found you can/must add it in the .cpp --- this adding to the namespace declarations from the .h --- before defining it via void RandomNumber::foo() { ... }.

            [I never had a question about some global/free someHelperFunction() function.]

            S Offline
            S Offline
            SimonSchroeder
            wrote on 8 Nov 2024, 07:50 last edited by
            #18

            @JonB said in To singleton or not to singleton, that is the question....:

            then I found you can/must add it in the .cpp --- this adding to the namespace declarations from the .h

            One of the nice things about namespaces is that you can reopen them as often as you want to. There are even a few cases where you are supposed to add something to namespace std.

            @JonB said in To singleton or not to singleton, that is the question....:

            they use types (copy or reference) as parameters/returns

            Just like pointers, references are also find and just need forward declarations. If your class has more than one or two member variables (of built-in type) it is most likely cheaper to use a reference instead of a copy. I only have very few cases where I'd want a copy of an object. That being said, I just noticed that I don't know if r-value references && also work with forward declarations. Does anybody know?

            J 1 Reply Last reply 8 Nov 2024, 12:26
            0
            • S SimonSchroeder
              8 Nov 2024, 07:50

              @JonB said in To singleton or not to singleton, that is the question....:

              then I found you can/must add it in the .cpp --- this adding to the namespace declarations from the .h

              One of the nice things about namespaces is that you can reopen them as often as you want to. There are even a few cases where you are supposed to add something to namespace std.

              @JonB said in To singleton or not to singleton, that is the question....:

              they use types (copy or reference) as parameters/returns

              Just like pointers, references are also find and just need forward declarations. If your class has more than one or two member variables (of built-in type) it is most likely cheaper to use a reference instead of a copy. I only have very few cases where I'd want a copy of an object. That being said, I just noticed that I don't know if r-value references && also work with forward declarations. Does anybody know?

              J Offline
              J Offline
              JoeCFD
              wrote on 8 Nov 2024, 12:26 last edited by
              #19

              @SimonSchroeder r-value references && work with forward declarations.

              1 Reply Last reply
              1
              • J jsulm
                7 Nov 2024, 06:07

                @JonB said in To singleton or not to singleton, that is the question....:

                Which do you prefer in your namespace .cpp file function definitions?

                For function definitions I prefer

                namespace Foo {
                
                void bar() { ... }
                
                void baz() { ... }
                
                }
                

                But if I use the functions I prefer to keep Foo:: prefix instead of using "using Foo;" directives.

                J Offline
                J Offline
                JoeCFD
                wrote on 8 Nov 2024, 12:29 last edited by JoeCFD 11 Aug 2024, 12:52
                #20

                @jsulm if void baz() is defined in two namespaces, Calling baz() with using "using Foo;" can cause confusing while two namespaces are present at the same place. Therefore, Foo:: prefix is preferred.

                namespace Foo1 {
                void baz() { ... }
                }
                
                namespace Foo2 {
                void baz() { ... }
                }
                
                In another class:
                
                using Foo1;
                using Foo2;
                
                void AnotheClass::testing()
                {
                        baz();  // not clear
                }
                
                ===================
                
                void AnotheClass::testing()
                {
                        Foo1::baz();  // clear
                }
                
                J S 2 Replies Last reply 8 Nov 2024, 13:06
                0
                • J JoeCFD
                  8 Nov 2024, 12:29

                  @jsulm if void baz() is defined in two namespaces, Calling baz() with using "using Foo;" can cause confusing while two namespaces are present at the same place. Therefore, Foo:: prefix is preferred.

                  namespace Foo1 {
                  void baz() { ... }
                  }
                  
                  namespace Foo2 {
                  void baz() { ... }
                  }
                  
                  In another class:
                  
                  using Foo1;
                  using Foo2;
                  
                  void AnotheClass::testing()
                  {
                          baz();  // not clear
                  }
                  
                  ===================
                  
                  void AnotheClass::testing()
                  {
                          Foo1::baz();  // clear
                  }
                  
                  J Offline
                  J Offline
                  JonB
                  wrote on 8 Nov 2024, 13:06 last edited by
                  #21

                  @JoeCFD ...which is why we don't risk using using... ;-)

                  1 Reply Last reply
                  0
                  • S Offline
                    S Offline
                    SimonSchroeder
                    wrote on 11 Nov 2024, 07:56 last edited by
                    #22

                    I agree that in general you should avoid using (for namespaces; now also allowed as a replacement for typedef).

                    There are, however, a few select places where I do use it for namespaces: 1) When using swap the preferred method is to using std::swap; (technically not a namespace) and then call swap unqualified (without a namespace, class name, etc). 2) For using string ""s and string view ""sv literals. Haven't used std::chrono much, but most likely would import the suffixes as well.

                    1 Reply Last reply
                    0
                    • J JoeCFD
                      8 Nov 2024, 12:29

                      @jsulm if void baz() is defined in two namespaces, Calling baz() with using "using Foo;" can cause confusing while two namespaces are present at the same place. Therefore, Foo:: prefix is preferred.

                      namespace Foo1 {
                      void baz() { ... }
                      }
                      
                      namespace Foo2 {
                      void baz() { ... }
                      }
                      
                      In another class:
                      
                      using Foo1;
                      using Foo2;
                      
                      void AnotheClass::testing()
                      {
                              baz();  // not clear
                      }
                      
                      ===================
                      
                      void AnotheClass::testing()
                      {
                              Foo1::baz();  // clear
                      }
                      
                      S Offline
                      S Offline
                      SimonSchroeder
                      wrote on 11 Nov 2024, 08:01 last edited by
                      #23

                      @JoeCFD said in To singleton or not to singleton, that is the question....:

                      Calling baz() with using "using Foo;" can cause confusing while two namespaces are present at the same place.

                      In the concrete example you have given, it would not compile because the compiler cannot resolve the overload (i.e. Foo1::baz or Foo2::baz). You'd still need to use a fully qualified name. It only gets confusing when you have Foo1::baz(int) and Foo2::baz(double). You might write baz(1); when you actually want to call Foo2::baz. The software might even do the right thing for years. Someone might just introduce Foo1::baz years down the line and suddenly the behavior changes.

                      1 Reply Last reply
                      1

                      23/23

                      11 Nov 2024, 08:01

                      • Login

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