The optimal implementation of C + + Singleton (single Case) mode

Source: Internet
Author: User
Tags log log

Reference: http://blog.yangyubo.com/2009/06/04/best-cpp-singleton-pattern/

Index

    • Static is not a singleton (Singleton) mode
    • A Hungry man mode
    • Lazy Mode (stack-rough Version)
    • Lazy mode (local static Variable-best Version)
    • Sample code and Considerations (optimal Implementation)
    • Extended Reading
    • Resources

I am very much in favor of the reasonable use of design patterns to make the code easier to understand and maintain, but I myself have little use of:-) except for the simple singleton (Singleton) Mode.

It is shameful that I did not find my singleton (Singleton) pattern and improved space until I read the C + + in Theory:the Singleton pattern and Part I Before.

Article author J. Nakamura lists the three ways to write a singleton (Singleton) pattern with the log log class:

Log.h#ifndef __log_h#define __log_h#include <list> #include <string>class LOG {public:  virtual void Write (char Const *logline);  virtual bool SaveTo (char const *FILENAME);P rivate:  std::list<std::string> m_data;}; #endif//__log_h
Static is not a singleton (Singleton) mode

A beginner may make mistakes, mistakenly think that all member variables and member methods are modified with static , that is, a singleton mode:

Class Log {public:  static void Write (char const *logline);  static bool SaveTo (char const *FILENAME);P rivate:  static std::list<std::string> m_data;};i n Log.cpp we need to addstd::list<std::string> log::m_data;

At first glance, there are many conditions for a singleton pattern, but it has some problems. first, the static member variable initialization order does not depend on the constructor, depends on the compiler mood, can not guarantee the initialization order (extreme situation: There is a b two member objects, b need to have a as the initialization parameters of the incoming, your Class is required to have constructors and to ensure initialization order).

second, the most serious problem, lost the face of the important characteristics of the object-"polymorphic", static member method can not be virtual . The subclass of the Log class cannot enjoy the convenience of "polymorphic".

A Hungry man mode

a hungry man mode is a singleton instance that is initialized immediately when the program is Run:

Class Log {public:  static log* Instance () {    return &m_pInstance;  }  virtual void Write (char const *logline);  virtual bool SaveTo (char const *FILENAME);P rivate:  Log ();              ctor is hidden  log (log const&);    Copy ctor is hidden  static Log m_pinstance;  Static std::list<std::string> m_data;};/ /in Log.cpp we had to Addlog log::m_pinstance;

The problem with this pattern is also obvious, the class is now polymorphic, but the initialization order of static member variables is not guaranteed.

It also raises another question (the real thing i've been through before, and I've been using the "lazy mode" mentioned below): there are two singleton patterns of classes Asingleton and Bsingleton, one day you want to Bsingleton Use the Asingleton instance in the constructor, which is a problem. Because the Bsingleton m_pinstance static object may be Asingleton One-Step call to initialize the constructor, the result asingleton::instance () An uninitialized memory area is returned, and the program simply collapses without running.

Lazy Mode (stack-rough Version)

J. Nakamura called it "gamma Singleton" because it was gamma in his famous << design pattern >> (<<design patterns>>) [gamma] a book using The Method. It is called "lazy mode" because the singleton instance is initialized only when it is used for the first time:

Class Log {public:  static log* Instance () {    if (!m_pinstance)      m_pinstance = new Log;    return m_pinstance;  }  virtual void Write (char const *logline);  virtual bool SaveTo (char const *FILENAME);P rivate:  Log ();        ctor is hidden  log (log const&);    Copy ctor is hidden  static log* m_pinstance;  Static std::list<std::string> m_data;};/ /in Log.cpp We has to addlog* log::m_pinstance = NULL;

Instance () allocates memory and initializes the m_pinstance only for the first time it is Called. well, It looks like all the problems are solved, the initialization order is guaranteed, and polymorphism is Ok.

But careful you may have found a problem when the program exits, the destructor is not executed. This can lead to resource leaks in some unreliable systems, such as file handles, socket connections, memory, and so On. fortunately, linux/windows 2000/xp and other commonly used systems can automatically release the system resources that are consumed when the program Exits. But this could still be a hidden danger, at least in J. Nakamura's impression that some systems are not automatically released.

The solution to this problem is to add a destructor () method to each Singleton class:

virtual BOOL destructor () {    //... release resource    if (null!= m_pinstance) {        Delete m_pinstance;        M_pinstance = NULL;}    }

Then make sure to call the destructor () method of each Singleton class when the program exits, which is reliable, but Cumbersome. fortunately, Master Meyers has a much simpler Approach.

Lazy mode (local static Variable-best Version)

It is also known as Meyers Singleton [Meyers]:

Class Log {public:  static log& Instance () {    static log thelog;    return thelog;  }  virtual void Write (char const *logline);  virtual bool SaveTo (char const *FILENAME);P rivate:  Log ();          ctor is hidden  log (log const&);      Copy ctor is hidden  log& operator= (Log const&);  Assign op is hidden  static std::list<std::string> m_data;};

The benefit of defining local static variables within the Instance () function is that the constructor of Thelog ' is initialized only at the first call to ' Instance () , which achieves the same dynamic initialization as the "stack version", ensuring that the member becomes The initialization order of the volume and Singleton itself.

It also has a potential security measure, Instance () Returns a reference to a local static variable, and if a pointer is returned, the caller of Instance () is likely to mistakenly assume that he is checking the validity of the pointer and is responsible for destroying it. Constructors and copy constructors are also privatized so that users of the class cannot instantiate Themselves.

In addition, several different Singleton instances have the same destructor sequence as the construction order.

Sample code and Considerations (optimal Implementation)

Replace the Singleton in the following C + + snippet with the actual class name to quickly get a singleton class:

Class Singleton {public:    static singleton& Instance () {        static Singleton thesingleton;        return thesingleton;    }    /* more (non-static) functions here */private:    Singleton ();                            ctor Hidden    Singleton (Singleton const&);            Copy ctor hidden    singleton& operator= (Singleton const&);//assign op. hidden    ~singleton ();                           Dtor hidden};

Note

  • Constructors for any two Singleton classes cannot refer to each Other's instances, or they can cause the program to Crash. Such as:

    asingleton& asingleton::instance () {    const bsingleton& b = bsingleton::instance ();    Static Asingleton thesingleton;    Return thesingleton;} bsingleton& bsingleton::instance () {    const Asingleton & b = asingleton::instance ();    Static Bsingleton thesingleton;    Return thesingleton;}
  • Must be used with caution in multi-threaded applications. If the unique instance has not yet been created, two threads call the creation method at the same time, and neither of them detects the existence of a unique instance, it creates an instance at the same time, so that two instances are constructed, violating the principle that the instance is unique in the singleton Pattern. The solution to this problem is to provide a mutex for the variable that indicates whether the class has been instantiated (although this reduces efficiency).

  • When multiple Singleton instances are referenced to each other, the destructor needs to be handled with Care. Such as: initialization order is Asingleton ? Bsingleton ? Csingleton of the three Singleton classes, where asingleton Bsingleton 's destructor calls the Csingleton Instance's member function, When the program exits, the Csingleton destructor will be called first, resulting in invalid instances, then the subsequent Asingleton Bsingleton will fail, causing the program to exit Unexpectedly.

Extended Reading
    • Anti-pattern: in practice the obvious but inefficient or need to optimize the design pattern, is to solve the problem with a common bad method. They have been researched and categorized to prevent future repetition and can be identified when developing systems that are not yet in Production. (some of these anti-patterns are quite interesting);
    • C + + in Theory:the Singleton pattern, part 2: "c + + in theory" series of the second section, the main content is the generic programming in the singleton mode, I am not too cold to generics, interested friends can See.
Resources
[Gamma] Design patterns:e.gamma, r.helm, R.johnson and J.vlissides.

The optimal implementation of C + + Singleton (single Case) mode

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.