c++ - सी++ सिंगलटन डिजाइन पैटर्न




design-patterns singleton (12)

आप स्मृति आवंटन से बच सकते हैं। कई प्रकार हैं, मल्टीथ्रेडिंग पर्यावरण के मामले में सभी को समस्याएं हैं।

मैं इस प्रकार के कार्यान्वयन को पसंद करता हूं (वास्तव में, यह सही ढंग से नहीं कहा जाता है कि मैं पसंद करता हूं, क्योंकि मैं जितना संभव हो सिंगलेट से बचता हूं):

class Singleton
{
private:
   Singleton();

public:
   static Singleton& instance()
   {
      static Singleton INSTANCE;
      return INSTANCE;
   }
};

इसमें कोई गतिशील स्मृति आवंटन नहीं है।

हाल ही में मैंने सी ++ के लिए सिंगलटन डिजाइन पैटर्न के अहसास / कार्यान्वयन में उछाल लिया है। ऐसा लगता है (मैंने इसे वास्तविक जीवन उदाहरण से अपनाया है):

// a lot of methods are omitted here
class Singleton
{
   public:
       static Singleton* getInstance( );
       ~Singleton( );
   private:
       Singleton( );
       static Singleton* instance;
};

इस घोषणा से मैं यह समझ सकता हूं कि उदाहरण क्षेत्र ढेर पर शुरू किया गया है। इसका मतलब है कि स्मृति आवंटन है। मेरे लिए पूरी तरह से अस्पष्ट क्या है जब वास्तव में स्मृति को हटा दिया जा रहा है? या क्या एक बग और मेमोरी रिसाव है? ऐसा लगता है कि कार्यान्वयन में कोई समस्या है।

मेरा मुख्य सवाल यह है कि, मैं इसे सही तरीके से कैसे कार्यान्वित करूं?


इस तरह के प्लेसमेंट का उपयोग करने के बारे में कैसे:

class singleton
{
    static singleton *s;
    static unsigned char *buffer[sizeof(singleton)/4 *4] //4 byte align
    static singleton* getinstance()
    {
        if (s == null)
        {
            s = new(buffer) singleton;
        }
        return s;
    }
};

एक अन्य गैर-आवंटन विकल्प: कक्षा C एक सिंगलटन बनाएं, जैसा कि आपको इसकी आवश्यकता है:

singleton<C>()

का उपयोग करते हुए

template <class X>
X& singleton()
{
    static X x;
    return x;
}

न तो यह और न ही कैटलिन का जवाब स्वचालित सी ++ में स्वचालित रूप से थ्रेड-सुरक्षित है, लेकिन सी ++ 0x में होगा।


क्या किसी ने std::call_once और std::once_flag उल्लेख किया है? अधिकतर अन्य दृष्टिकोण - डबल चेक लॉकिंग सहित - टूटा हुआ है।

सिंगलटन पैटर्न कार्यान्वयन में एक बड़ी समस्या सुरक्षित प्रारंभिक है। सिंक्रनाइज़िंग बाधाओं के साथ प्रारंभिक अनुक्रम की रक्षा करना एकमात्र सुरक्षित तरीका है। लेकिन उन बाधाओं को स्वयं को सुरक्षित रूप से शुरू करने की आवश्यकता है। std::once_flag गारंटीकृत सुरक्षित प्रारंभिकता प्राप्त करने के लिए तंत्र है।


मुझे जवाबों में सीआरटीपी कार्यान्वयन नहीं मिला, इसलिए यहां यह है:

template<typename HeirT>
class Singleton
{
public:
    Singleton() = delete;

    Singleton(const Singleton &) = delete;

    Singleton &operator=(const Singleton &) = delete;

    static HeirT &instance()
    {
        static HeirT instance;
        return instance;
    }
};

इसका उपयोग करने के लिए बस अपनी कक्षा को इस तरह से प्राप्त करें, जैसे: class Test : public Singleton<Test>


मुझे लगता है कि आपको एक स्थैतिक फ़ंक्शन लिखना चाहिए जिसमें आपकी स्थिर वस्तु हटा दी गई हो। जब आप अपना आवेदन बंद करने वाले हैं तो आपको यह फ़ंक्शन कॉल करना चाहिए। यह सुनिश्चित करेगा कि आपके पास स्मृति रिसाव नहीं है।


यह ऑब्जेक्ट लाइफ-टाइम प्रबंधन के बारे में है। मान लीजिए कि आपके सॉफ़्टवेयर में सिंगलेट्स से अधिक है। और वे लॉगर सिंगलटन पर निर्भर करते हैं। आवेदन विनाश के दौरान, मान लीजिए कि एक और सिंगलटन ऑब्जेक्ट लॉगर का उपयोग अपने विनाश चरणों को लॉग करने के लिए करता है। आपको गारंटी देनी होगी कि लॉगर को आखिरी बार साफ किया जाना चाहिए। इसलिए, कृपया इस पेपर को भी देखें: http://www.cs.wustl.edu/~schmidt/PDF/ObjMan.pdf


यह वास्तव में ढेर से आवंटित किया जाता है, लेकिन स्रोतों के बिना जानने का कोई तरीका नहीं है।

ठेठ कार्यान्वयन (कुछ कोड जो मैंने पहले से ही emacs में लिया है) होगा:

Singleton * Singleton::getInstance() {
    if (!instance) {
        instance = new Singleton();
    };
    return instance;
};

... और बाद में साफ करने के लिए गुंजाइश से बाहर जाने वाले कार्यक्रम पर भरोसा करें।

यदि आप ऐसे मंच पर काम करते हैं जहां क्लीनअप मैन्युअल रूप से किया जाना चाहिए, तो शायद मैं मैन्युअल क्लीनअप दिनचर्या जोड़ूंगा।

ऐसा करने के साथ एक और मुद्दा यह है कि यह थ्रेड-सुरक्षित नहीं है। एक बहुप्रचारित माहौल में, दो थ्रेड "अगर" के माध्यम से प्राप्त हो सकते हैं या तो नए उदाहरण आवंटित करने का मौका मिलने से पहले (इसलिए दोनों चाहते हैं)। यदि आप किसी भी तरह से साफ करने के लिए प्रोग्राम समाप्ति पर भरोसा कर रहे हैं, तो यह अभी भी एक सौदे का बड़ा नहीं है।


यहां एक आसान कार्यान्वयन है।

#include <Windows.h>
#include <iostream>

using namespace std;


class SingletonClass {

public:
    static SingletonClass* getInstance() {

    return (!m_instanceSingleton) ?
        m_instanceSingleton = new SingletonClass : 
        m_instanceSingleton;
    }

private:
    // private constructor and destructor
    SingletonClass() { cout << "SingletonClass instance created!\n"; }
    ~SingletonClass() {}

    // private copy constructor and assignment operator
    SingletonClass(const SingletonClass&);
    SingletonClass& operator=(const SingletonClass&);

    static SingletonClass *m_instanceSingleton;
};

SingletonClass* SingletonClass::m_instanceSingleton = nullptr;



int main(int argc, const char * argv[]) {

    SingletonClass *singleton;
    singleton = singleton->getInstance();
    cout << singleton << endl;

    // Another object gets the reference of the first object!
    SingletonClass *anotherSingleton;
    anotherSingleton = anotherSingleton->getInstance();
    cout << anotherSingleton << endl;

    Sleep(5000);

    return 0;
}

केवल एक ऑब्जेक्ट बनाया गया है और यह ऑब्जेक्ट संदर्भ हर बार बाद में लौटा दिया जाता है।

SingletonClass instance created!
00915CB8
00915CB8

यहां 00 9 15 सीबी 8 प्रोग्राम की अवधि के लिए सिंगलटन ऑब्जेक्ट का स्मृति स्थान है, लेकिन प्रोग्राम (आमतौर पर!) प्रत्येक बार प्रोग्राम चलाए जाने पर अलग होता है।

एनबी यह एक थ्रेड सुरक्षित नहीं है। आपको थ्रेड सुरक्षा सुनिश्चित करना है।


यहां बहुत सारे जवाब हैं और कुछ समय पहले पूछा गया था लेकिन मैं निम्नलिखित जोड़ना चाहता हूं। एलन और पॉल एज़स्ट को क्रेडिट। ( क्यूटी के साथ सी ++ में पैटर्न डिजाइन करने के लिए एक परिचय )

सिंगलटन पैटर्न उन परिस्थितियों में उपयोग किया जाने वाला एक विशेष कारखाना है जहां आप बनाए गए उदाहरणों या प्रकारों को सीमित करना चाहते हैं। ग्राहकफैक्टरी :: उदाहरण () विधि, नीचे परिभाषित एक उदाहरण ओए सिंगलटन कारखाना है। यदि आवश्यक हो तो यह एक वस्तु बनाता है, लेकिन केवल पहली बार विधि कहा जाता है। बाद के कॉल पर यह हमेशा एक ही ऑब्जेक्ट पर पॉइंटर देता है।

CustomerFactory* CustomerFactory::instance(){
   static CustomerFactory* retval = 0;
   if (retval == 0) retval = new CustomerFactory(qApp);          1
   return retval;
}

1 इस वस्तु को सुनिश्चित करता है और QAplication बाहर निकलने पर उसके सभी बच्चे साफ़ हो जाते हैं।

हेप ऑब्जेक्ट्स से निपटने के दौरान मेमोरी लीक छोड़ने के लिए यह महत्वपूर्ण है। आप इस संबंध में सहायता के लिए QObjects माता-पिता-संबंध संबंधों का उपयोग कर सकते हैं।


स्वीकार्य उत्तर में समाधान में एक महत्वपूर्ण कमी है - नियंत्रण के बाद सिंगलटन के विनाशक को "मुख्य" फ़ंक्शन छोड़ने के बाद बुलाया जाता है। वास्तव में समस्याएं हो सकती हैं, जब कुछ निर्भर वस्तुओं को "मुख्य" के अंदर आवंटित किया जाता है।

क्यूटी आवेदन में सिंगलटन पेश करने की कोशिश करते समय, मैंने इस समस्या से मुलाकात की। मैंने फैसला किया कि मेरे सभी सेटअप संवाद सिंगलेट्स होना चाहिए, और ऊपर दिए गए पैटर्न को अपनाया जाना चाहिए। दुर्भाग्यवश, क्यूटी की मुख्य कक्षा "क्यूएप्लिकेशन" को "मुख्य" फ़ंक्शन में ढेर पर आवंटित किया गया था, और क्यूटी ने कोई ऑब्जेक्ट ऑब्जेक्ट उपलब्ध होने पर संवाद बनाने / नष्ट करने से मना कर दिया है।

यही कारण है कि मैं ढेर-आवंटित सिंगलेट्स पसंद करता हूं। मैं सभी सिंगलेट्स के लिए एक स्पष्ट "init ()" और "शब्द ()" विधियां प्रदान करता हूं और उन्हें "मुख्य" के अंदर बुलाता हूं। इस प्रकार मेरे पास सिंगलटन निर्माण / विनाश के आदेश पर पूर्ण नियंत्रण है, और मैं यह भी गारंटी देता हूं कि सिंगलेट्स बनाए जाएंगे, इससे कोई फर्क नहीं पड़ता कि किसी को "getInstance ()" कहा जाता है या नहीं।


@ लोकी अस्थारी का जवाब उत्कृष्ट है।

हालांकि कई स्थैतिक वस्तुओं के साथ कई बार आपको यह गारंटी देने में सक्षम होना चाहिए कि सिंगलटन को तब तक नष्ट नहीं किया जाएगा जब तक कि आपके सभी स्थिर ऑब्जेक्ट्स जो सिंगलटन का उपयोग न करें, अब इसकी आवश्यकता नहीं है।

इस मामले में std::shared_ptr का उपयोग सभी उपयोगकर्ताओं के लिए सिंगलटन को जीवित रखने के लिए भी किया जा सकता है, भले ही स्थिर विनाशकों को कार्यक्रम के अंत में बुलाया जा रहा हो:

class Singleton
{
public:
    Singleton(Singleton const&) = delete;
    Singleton& operator=(Singleton const&) = delete;

    static std::shared_ptr<Singleton> instance()
    {
        static std::shared_ptr<Singleton> s{new Singleton};
        return s;
    }

private:
    Singleton() {}
};




singleton