C++ Singleton Pattern

Discussion in 'C++' started by wkaras@yahoo.com, Dec 13, 2006.

  1. Guest

    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"?
    , Dec 13, 2006
    #1
    1. Advertising

  2. 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
    Victor Bazarov, Dec 13, 2006
    #2
    1. Advertising

  3. Salt_Peter Guest

    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()
    */
    Salt_Peter, Dec 13, 2006
    #3
  4. 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
    Emmanuel Deloget, Dec 13, 2006
    #4
  5. Guest

    Salt_Peter wrote:
    > 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?
    , Dec 13, 2006
    #5
  6. Guest

    Emmanuel Deloget wrote:
    > 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.
    , Dec 13, 2006
    #6
  7. 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
    Victor Bazarov, Dec 13, 2006
    #7
  8. 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.
    Gianni Mariani, Dec 13, 2006
    #8
  9. Guest

    Victor Bazarov wrote:
    > 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.
    , Dec 13, 2006
    #9
  10. 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.
    Gianni Mariani, Dec 13, 2006
    #10
  11. Fei Liu Guest

    wrote:
    > Victor Bazarov wrote:
    >> 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
    Fei Liu, Dec 15, 2006
    #11
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Proton Projects - Moin

    Singleton - Whether Cloneable overrides Singleton

    Proton Projects - Moin, Mar 26, 2007, in forum: Java
    Replies:
    4
    Views:
    3,236
    Proton Projects - Moin
    Mar 27, 2007
  2. Wilhelm
    Replies:
    1
    Views:
    162
  3. Trans
    Replies:
    12
    Views:
    273
    Robert Klemme
    Sep 14, 2007
  4. Paul McMahon
    Replies:
    3
    Views:
    204
    David A. Black
    Jun 9, 2008
  5. Charles Oliver Nutter

    Singleton methods without the singleton class

    Charles Oliver Nutter, Mar 15, 2010, in forum: Ruby
    Replies:
    4
    Views:
    199
    Charles Oliver Nutter
    Mar 22, 2010
Loading...

Share This Page