C++ Singleton Pattern

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • wkaras@yahoo.com

    C++ Singleton Pattern

    Why aren't "Singletons " done like this in C++:

    A.hpp:

    class A
    {
    public: static A theA;

    // ...

    private:
    A() { /* ... */ }
    };

    A.cpp:

    A A::theA;

    rather than the complicated approaches I've
    seen with the instance being allocated with "new"?

  • Victor Bazarov

    #2
    Re: C++ Singleton Pattern

    wkaras@yahoo.co m wrote:
    Why aren't "Singletons " done like this in C++:
    >
    A.hpp:
    >
    class A
    {
    public: static A theA;
    >
    // ...
    >
    private:
    A() { /* ... */ }
    };
    >
    A.cpp:
    >
    A A::theA;
    >
    rather than the complicated approaches I've
    seen with the instance being allocated with "new"?
    Actually some of them are. Why do you say they aren't?

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask


    Comment

    • Salt_Peter

      #3
      Re: C++ Singleton Pattern


      wkaras@yahoo.co m wrote:
      Why aren't "Singletons " done like this in C++:
      >
      A.hpp:
      >
      class A
      {
      public: static A theA;
      >
      // ...
      >
      private:
      A() { /* ... */ }
      };
      >
      A.cpp:
      >
      A A::theA;
      Whats stopying me from copying an instance of A?

      int main()
      {
      A b(A::theA);
      }
      >
      rather than the complicated approaches I've
      seen with the instance being allocated with "new"?
      How about:

      #include <iostream>
      #include <ostream>

      template< typename T >
      T& instance() // by reference only
      {
      static T t;
      return t;
      }

      class A {
      friend A& instance< A >();
      A() { std::cout << "A()\n"; }
      A(const A& copy) { std::cout << "copy A\n"; }
      public:
      ~A() { std::cout << "~A()\n"; }
      };

      int main()
      {
      A& r_a = instance< A >();
      // A a = instance< A >(); // error
      std::cout << "&r_a = " << &r_a << std::endl;
      A& r_b = instance< A >();
      std::cout << "&r_b = " << &r_b << std::endl;
      }

      /*
      A()
      &r_a = 0x501fe0
      &r_b = 0x501fe0
      ~A()
      */

      Comment

      • Emmanuel Deloget

        #4
        Re: C++ Singleton Pattern

        wkaras@yahoo.co m a écrit :
        Why aren't "Singletons " done like this in C++:
        >
        A.hpp:
        >
        class A
        {
        public: static A theA;
        private:
        A() { /* ... */ }
        };
        >
        A.cpp:
        >
        A A::theA;
        >
        rather than the complicated approaches I've
        seen with the instance being allocated with "new"?
        Your approach is dangerous, as you don't know when the object is
        created. You are only able to successfully use it after you entered in
        main(), and you should not use it after main() exit. It means that your
        singleton cannot be used in static object construction and so on - note
        that this might not be a problem in the end.

        Meyer's singleton (the getInstance() function declares a static
        variable and returns this variable) was probably what you got in mind -
        the standard ensures that the static is constructed the first time you
        entered in the function, so it is always valid - until you quit main()
        (static objects order of destruction is well defined, but not easily
        handled from the programmer point of view, so you'd better not use it
        after you exit main()). Allocating the instance using new() in the
        getInstance() function allows the same use as Meyer's singleton, but
        the singleton is still valid until the memory is freed. If it is never
        freed then you singleton is always valid.

        * Your approach
        class A
        {
        private:
        static A theA;
        A() { }
        ~A() { }
        A(const A&) { }
        A& operator=(const A&);
        public:
        // time of construction is not known by the programmer
        // time of destruction is not known by the programmer
        A& instance() { return theA; }
        };

        * Meyer's approach
        class A
        {
        private:
        A() { }
        ~A() { }
        A(const A&) { }
        A& operator=(const A&);
        public:
        // the instance will be created when you enter the
        // function for the first time
        // time of destruction is hard to tell from the programmer
        // point of view
        A& instance() { static A a; return a; }
        };

        * GoF approach:
        class A
        {
        private:
        A() { }
        ~A() { }
        A(const A&) { }
        A& operator=(const A&);
        public:
        // the instance will be created when you enter the
        // function for the first time
        // the instance is never destroyed
        A& instance() { static A *a = NULL; if (!a) a = new A(); return a; }
        };

        There's a very interesting discussion about singleton and their
        possible implementation in the Modern C++ book of Andrei Alexandrescu.

        Regards,

        -- Emmanuel Deloget, Artware

        Comment

        • wkaras@yahoo.com

          #5
          Re: C++ Singleton Pattern

          Salt_Peter wrote:
          wkaras@yahoo.co m wrote:
          Why aren't "Singletons " done like this in C++:

          A.hpp:

          class A
          {
          public: static A theA;

          // ...

          private:
          A() { /* ... */ }
          };

          A.cpp:

          A A::theA;
          >
          Whats stopying me from copying an instance of A?
          >
          int main()
          {
          A b(A::theA);
          }
          >
          Yes, good point, I forgot the private undefined copy constructor.

          rather than the complicated approaches I've
          seen with the instance being allocated with "new"?
          >
          How about:
          >
          #include <iostream>
          #include <ostream>
          >
          template< typename T >
          T& instance() // by reference only
          {
          static T t;
          return t;
          }
          >
          class A {
          friend A& instance< A >();
          A() { std::cout << "A()\n"; }
          A(const A& copy) { std::cout << "copy A\n"; }
          public:
          ~A() { std::cout << "~A()\n"; }
          };
          So the reason for this is to avoid having, for classes with
          all inline member functions (the exceptional case i would
          think), a .cpp file that defines the single private instance?

          Comment

          • wkaras@yahoo.com

            #6
            Re: C++ Singleton Pattern

            Emmanuel Deloget wrote:
            wkaras@yahoo.co m a écrit :
            >
            Why aren't "Singletons " done like this in C++:

            A.hpp:

            class A
            {
            public: static A theA;
            private:
            A() { /* ... */ }
            };

            A.cpp:

            A A::theA;

            rather than the complicated approaches I've
            seen with the instance being allocated with "new"?
            >
            Your approach is dangerous, as you don't know when the object is
            created. You are only able to successfully use it after you entered in
            main(), and you should not use it after main() exit. It means that your
            singleton cannot be used in static object construction and so on - note
            that this might not be a problem in the end.
            >
            Meyer's singleton (the getInstance() function declares a static
            variable and returns this variable) was probably what you got in mind -
            the standard ensures that the static is constructed the first time you
            entered in the function, so it is always valid - until you quit main()
            (static objects order of destruction is well defined, but not easily
            handled from the programmer point of view, so you'd better not use it
            after you exit main()). Allocating the instance using new() in the
            getInstance() function allows the same use as Meyer's singleton, but
            the singleton is still valid until the memory is freed. If it is never
            freed then you singleton is always valid.
            >
            * Your approach
            class A
            {
            private:
            static A theA;
            A() { }
            ~A() { }
            A(const A&) { }
            A& operator=(const A&);
            public:
            // time of construction is not known by the programmer
            // time of destruction is not known by the programmer
            A& instance() { return theA; }
            };
            >
            * Meyer's approach
            class A
            {
            private:
            A() { }
            ~A() { }
            A(const A&) { }
            A& operator=(const A&);
            public:
            // the instance will be created when you enter the
            // function for the first time
            // time of destruction is hard to tell from the programmer
            // point of view
            A& instance() { static A a; return a; }
            };
            My understanding is that the standard allows local statics to
            be initialized any time before the line of executable code
            following their definition is executed. So I don't see how
            this addresses the order-of-intialization problem.
            * GoF approach:
            class A
            {
            private:
            A() { }
            ~A() { }
            A(const A&) { }
            A& operator=(const A&);
            public:
            // the instance will be created when you enter the
            // function for the first time
            // the instance is never destroyed
            A& instance() { static A *a = NULL; if (!a) a = new A(); return a; }
            };
            I dislike this because of the added overhead to every single access
            to the instance.

            (Insert by reference here any of the long heated threads about
            whether minor optimizations are worth it.)

            The are also cases where the fact that the instance is not
            destroyed can be a problem. If the instance sets some
            sort of lock flag in a file or in a shared memory segment,
            the file will close/segment will detach on program exit,
            but the lock flag won't be cleared.

            Comment

            • Victor Bazarov

              #7
              Re: C++ Singleton Pattern

              wkaras@yahoo.co m wrote:
              [..]
              My understanding is that the standard allows local statics to
              be initialized any time before the line of executable code
              following their definition is executed. So I don't see how
              this addresses the order-of-intialization problem.
              Your understanding is incorrect. The local statics are initialised
              when the control passes their initialisation for the first time.
              [..]
              V
              --
              Please remove capital 'A's when replying by e-mail
              I do not respond to top-posted replies, please don't ask


              Comment

              • Gianni Mariani

                #8
                Re: C++ Singleton Pattern

                Emmanuel Deloget wrote:
                .....
                // the instance will be created when you enter the
                // function for the first time
                // the instance is never destroyed
                A& instance() { static A *a = NULL; if (!a) a = new A(); return a; }
                // is this not the same ?
                A& instance() { static A *a = new A(); return *a; }

                With gcc, this is also thread-safe.

                Comment

                • wkaras@yahoo.com

                  #9
                  Re: C++ Singleton Pattern

                  Victor Bazarov wrote:
                  wkaras@yahoo.co m wrote:
                  [..]
                  My understanding is that the standard allows local statics to
                  be initialized any time before the line of executable code
                  following their definition is executed. So I don't see how
                  this addresses the order-of-intialization problem.
                  >
                  Your understanding is incorrect. The local statics are initialised
                  when the control passes their initialisation for the first time.
                  ....

                  Since you likely know the case-law on this much better than
                  me, I will take your word on this. Looking at Draft 98, 6.7-4
                  seems to unnecessary go around the block a few times.
                  Why not just say local statics are intialized when control
                  passes them, undefined value before initialization, and let
                  the as-if rule allow for optimized early initialization?

                  The implication of this is that the compiler has to generate
                  a hidden static flag to prevent re-initialization, and that flag
                  has to be checked every time control passes the local static
                  definition.

                  Comment

                  • Gianni Mariani

                    #10
                    Re: C++ Singleton Pattern

                    wkaras@yahoo.co m wrote:
                    ....
                    The implication of this is that the compiler has to generate
                    a hidden static flag to prevent re-initialization, and that flag
                    has to be checked every time control passes the local static
                    definition.
                    Wait until you read about the order of destruction.

                    Comment

                    • Fei Liu

                      #11
                      Re: C++ Singleton Pattern

                      wkaras@yahoo.co m wrote:
                      Victor Bazarov wrote:
                      >wkaras@yahoo.co m wrote:
                      >>[..]
                      >>My understanding is that the standard allows local statics to
                      >>be initialized any time before the line of executable code
                      >>following their definition is executed. So I don't see how
                      >>this addresses the order-of-intialization problem.
                      >Your understanding is incorrect. The local statics are initialised
                      >when the control passes their initialisation for the first time.
                      ...
                      >
                      Since you likely know the case-law on this much better than
                      me, I will take your word on this. Looking at Draft 98, 6.7-4
                      seems to unnecessary go around the block a few times.
                      Why not just say local statics are intialized when control
                      passes them, undefined value before initialization, and let
                      the as-if rule allow for optimized early initialization?
                      >
                      The implication of this is that the compiler has to generate
                      a hidden static flag to prevent re-initialization, and that flag
                      has to be checked every time control passes the local static
                      definition.
                      >
                      [Offtopic]
                      Standard only defines the behavior of local static variables. But how
                      it's achieved is highly implementation specific. In the real world,
                      local static variables are implemented like global static variables
                      (with/wo slight difference in the segments they initially occupy), they
                      have guaranteed memory storage by compiler. Linker looks them up and
                      generates relocatable code in the end.

                      Fei

                      Comment

                      Working...