2009-09-23 25 views
45

आज मेरे एक दोस्त ने मुझसे पूछा कि वह वैश्विक स्थिर वस्तु पर सिंगलटन का उपयोग क्यों करना चाहिए? जिस तरीके से मैंने इसे समझाया था, वह था कि सिंगलटन में राज्य बनाम स्थैतिक वैश्विक वस्तु नहीं होगी ... लेकिन फिर मुझे यकीन नहीं था .. क्योंकि यह सी ++ में है .. (मैं सी # से आ रहा था)सी ++ सिंगलटन बनाम वैश्विक स्थैतिक वस्तु

दूसरे पर एक के फायदे क्या हैं? (सी ++ में)

उत्तर

21

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

एक सभ्य सारांश here है।

+0

और फिर आप जटिल दौड़ की स्थिति पेश करते हैं और थ्रेड सुरक्षा को फेंक देते हैं क्योंकि दो धागे एक साथ उस समारोह को कॉल कर सकते हैं। – jalf

+1

एक सादा पुरानी वैश्विक वस्तु होने के बावजूद, पर्याप्त रूप से पर्याप्त, std :: cout looks ठीक काम करने के लिए ... मुझे यकीन है कि प्रारंभिकरण का आदेश इतनी बड़ी समस्या थी, मानक समिति अब तक ध्यान देगी।यदि आप ग्लोबल्स का उपयोग करते हैं और उन्हें एक-दूसरे पर निर्भर करते हैं तो यह केवल एक समस्या है। – jalf

+1

@jalf: अपना होमवर्क करें। 'cout' और' cin' को मानक द्वारा 'मुख्य() 'से पहले विशेष रूप से निर्दिष्ट करने के लिए निर्दिष्ट किया गया है। अन्य वैश्विक वस्तुओं को यह उपचार नहीं मिलता है। इसके अलावा, थ्रेड-सुरक्षित सिंगलटन कार्यान्वयन मौजूद हैं और खुद को लिखना मुश्किल नहीं है; डबल-निर्माण को रोकने के लिए आपको केवल डबल-लॉक की आवश्यकता है। व्यक्तिगत रूप से मैं सिंगलेट से बचने की कोशिश करता हूं, मुझे लगता है कि पैटर्न का उपयोग अधिक हो गया है। लेकिन सी ++ ज्ञान की आपकी कमी मुझे कम करने का कोई कारण नहीं है। – rlbond

52

असल में, सी ++ पसंदीदा तरीका स्थानीय स्थैतिक वस्तु है।

Printer & thePrinter() { 
    static Printer printer; 
    return printer; 
} 

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

new पर कॉल करके नया उदाहरण बनाने के साथ सिंगलटन करने के सामान्य तरीके से बेहतर क्या होता है यह है कि ऑब्जेक्ट विनाशक को प्रोग्राम के अंत में बुलाया जाएगा। यह गतिशील आवंटित सिंगलटन के साथ नहीं होगा।

एक और सकारात्मक पक्ष यह है कि एकल स्थिरता या उप-वर्गों से भी, इसे बनाने से पहले सिंगलटन तक पहुंचने का कोई तरीका नहीं है। आपको कुछ डिबगिंग समय बचाता है।

+7

यह सिंगलेट बनाने का सबसे अच्छा तरीका है। वास्तविक कोड में नया उपयोग करना आम नहीं है, हालांकि इंटरनेट पर बहुत सारे उदाहरण हैं जो दिखाते हैं कि यह अच्छा विचार है (उन पर विश्वास न करें)। –

+3

वास्तव में, सिंगलेट बनाने का कोई "सर्वश्रेष्ठ" तरीका नहीं है। यदि यह सिंगलटन अपने विनाशक में एक और सिंगलटन का संदर्भ देता है, तो यह ठीक से काम नहीं करेगा। – rlbond

+2

ध्यान दें कि यह आम तौर पर थ्रेड-सुरक्षित नहीं है (कार्यान्वयन पर निर्भर करता है: उदाहरण के लिए g ++ ताले डालेगा, लेकिन एमएसवीसी नहीं होगा)। –

3

कारण 1:
सिंगलेटन बनाना आसान है ताकि वे आलसी निर्माण कर सकें।
जबकि आप इसे ग्लोबल्स के साथ कर सकते हैं, यह डेवलपर द्वारा अतिरिक्त कार्य करता है। इसलिए डिफ़ॉल्ट ग्लोबल्स द्वारा हमेशा प्रारंभ किया जाता है (नामस्थानों के साथ कुछ विशेष नियमों के अलावा)।

तो यदि आपका ऑब्जेक्ट बड़ा और/या महंगा बनाने के लिए महंगा है, तो आप इसे तब तक बनाना नहीं चाहेंगे जब तक कि आपको वास्तव में इसका उपयोग नहीं करना पड़े।

कारण 2:
प्रारंभिकरण (और विनाश) समस्या का आदेश।

GlobalRes& getGlobalRes() 
{ 
    static GlobalRes instance; // Lazily initialized. 
    return instance; 
} 


GlobalResTwo& getGlobalResTwo() 
{ 
    static GlobalResTwo instance; // Lazy again. 
    return instance; 
} 


// Order of destruction problem. 
// The destructor of this object uses another global object so 
// the order of destruction is important. 
class GlobalResTwo 
{ 
    public: 
     GlobalResTwo() 
     { 
      getGlobalRes(); 
      // At this point globalRes is fully initialized. 
      // Because it is fully initialized before this object it will be destroyed 
      // after this object is destroyed (Guaranteed) 
     } 
     ~GlobalResTwo() 
     { 
      // It is safe to use globalRes because we know it will not be destroyed 
      // before this object. 
      getGlobalRes().doStuff(); 
     } 
}; 
2

सिंगलटन का उपयोग करना मुहावरा ("पहले उपयोग पर निर्माण"), आप static initialization order fiasco

+1

वह लेख भयानक है। प्रस्तावित समाधान समस्या के रूप में बुरा है। फ़ंक्शन में नया उपयोग करके आप अब विनाशक को कभी नहीं बुलाएंगे। –

+1

यह बहुत कम स्थितियों में से एक है जहां स्मृति रिसाव ठीक है, क्योंकि कार्यक्रम किसी भी तरह से समाप्त हो रहा है (जब तक कि आप वास्तव में भयानक ओएस पर नहीं हैं जो किसी भी तरह स्मृति को पुनः प्राप्त नहीं करता है)। यदि आप पढ़ते हैं, तो अगला एफएक्यू, वह बताता है कि क्यों। – coppro

+1

कृपया अनुभाग 10.12 से 10.16 –

2

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

तुलनात्मक रूप से, वैश्विक स्थैतिक वस्तु के साथ, डेवलपर लेखन कोड को रोकना कुछ भी नहीं होगा जो इस ऑब्जेक्ट का एक अतिरिक्त उदाहरण बनाता है।

अतिरिक्त बाधा का लाभ यह है कि आपके पास इस बात की गारंटी है कि ऑब्जेक्ट का उपयोग कैसे किया जाएगा।

+1

"कंपाइलर ने निर्देश दिया है कि" केवल एक ही हो सकता है " एक ही उपयोग के मामले में आने की देखभाल जहां यह ** अच्छी ** चीज है? आपके कोड में मनमाने ढंग से और अनावश्यक बाधाओं को जोड़ने का लाभ नहीं है।यह एक लाभ है यदि आपका कोड * सामान्य * और * पुन: प्रयोज्य * है, और यह नहीं होगा कि यदि आप पहली चीज करते हैं तो उस पर बाधाओं को थप्पड़ मारना आपको आवश्यकता नहीं है। – jalf

+0

@jalf: अधिकांश कोड सामान्य और पुन: प्रयोज्य होना चाहिए। लेकिन एक बड़े आवेदन में आप कई वस्तुओं को प्राप्त कर सकते हैं जिनमें कुछ केंद्रीय संदर्भ - वैश्विक अनुप्रयोग ढांचे की आवश्यकता होती है। एक उदाहरण कुछ प्रकार का लॉक मैनेजर होगा। अपने स्वयं के लॉक प्रबंधकों को बनाने वाले एप्लिकेशन के विभिन्न हिस्सों अनुचित होंगे। –

+0

नहीं, आप अलग-अलग घटकों के लिए आसानी से अलग लॉक प्रबंधक प्राप्त कर सकते हैं। – jalf

0

सी ++ में, वास्तविक उपयोगिता के मामले में दोनों के बीच बहुत अधिक अंतर नहीं है। एक वैश्विक वस्तु निश्चित रूप से अपने राज्य को बनाए रख सकती है (संभवतः अन्य वैश्विक चर के साथ, हालांकि मैं इसकी अनुशंसा नहीं करता)।यदि आप ग्लोबल या सिंगलटन (और इसके कई कारण नहीं हैं) का उपयोग करने जा रहे हैं, तो ग्लोबल ऑब्जेक्ट पर सिंगलटन का उपयोग करने का सबसे बड़ा कारण यह है कि सिंगलटन के साथ, आप कई वर्गों को विरासत में रखते हुए गतिशील बहुरूपता प्राप्त कर सकते हैं एक सिंगलटन बेस क्लास।

+0

यह बहुरूपता कैसे कार्यान्वित की जाएगी, और कुछ उपयोग-मामले क्या हैं? –

-1

ठीक है, वास्तव में सिंगलटन के साथ जाने के दो कारण हैं। एक स्थिर आदेश है जो हर किसी के बारे में बात कर रहा है।

CoolThing blah; 
gs_coolGlobalStaticThing = blah; 

या, और भी बदतर:

gs_coolGlobalStaticThing = {}; 

कैप्सूलीकरण पहलू बेवकूफों और दुर्भावनापूर्ण से अपने उदाहरण की रक्षा करेगा

अन्य अपने कोड का उपयोग कुछ इस तरह करने से किसी को रोकने के लिए है झटके।

+0

आप एक्सेसर्स दोस्त के बारे में बात कर रहे हैं ... –

7

आज मेरे एक दोस्त ने मुझसे पूछा कि वह वैश्विक स्थिर वस्तु पर सिंगलटन का उपयोग क्यों करना चाहिए? जिस तरह से मैंने इसे समझाया था, यह था कि सिंगलटन में राज्य बनाम स्थैतिक वैश्विक वस्तु नहीं होगी ... लेकिन फिर मुझे यकीन नहीं था .. क्योंकि यह सी ++ में है .. (मैं सी # से आ रहा था)

एक स्थिर वैश्विक वस्तु के रूप में अच्छी तरह से सी # में राज्य हो सकता है:

class myclass { 
// can have state 
// ... 
public static myclass m = new myclass(); // globally accessible static instance, which can have state 
} 

क्या फायदे एक दूसरे के ऊपर कर रहे हैं? (सी ++ में)

एक सिंगलटन आपके कोड को अपंग करता है, एक वैश्विक स्थिर उदाहरण नहीं है। अकेले सिंगलेट्स की समस्याओं के बारे में SO पर अनगिनत प्रश्न हैं। Here's one, and another, or another

  • तक पहुँच सुलभ वस्तु, और
  • एक गारंटी केवल एक उदाहरण बनाया जा सकता है कि:

    संक्षेप में, एक सिंगलटन आपको दो बातें देता है।

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

+0

सिंगलटन पैटर्न के लिए कुछ वैध उपयोग हैं। यह अत्यधिक उपयोग किया गया है, लेकिन कुछ ऐसे मामले हैं जहां यह ठीक है (कुछ उदाहरण: एक गेम के लिए एक वैश्विक आरएनजी। कॉन्फ़िगरेशन विकल्प ऑब्जेक्ट। मेमोरी पूल नियंत्रक।) – rlbond

+0

और जैसा कि मैंने ऊपर बताया है, विभिन्न संकलन इकाइयों में वस्तुओं के निर्माण का क्रम अनिर्धारित है । आपने मुझ पर विश्वास नहीं किया और 'cout' और' cin' लाया, लेकिन ये मानक द्वारा परिभाषित विशेष मामले हैं। – rlbond

+0

कोई कारण नहीं है कि गेम को एक वैश्विक आरएनजी का उपयोग क्यों करना चाहिए। विवाद को कम क्यों न करें और प्रति धागा एक है? और आप प्रति उपप्रणाली को एक अलग भी चाहते हैं। या प्रति खिलाड़ी, एक मल्टीप्लेयर परिदृश्य में। कॉन्फ़िगरेशन विकल्प? मैं आसानी से दो के लिए उपयोग देख सकते हैं। आपके पास कॉन्फ़िगरेशन का एक सेट है जो सक्रिय हैं, और दूसरा सेट जो उपयोगकर्ता वर्तमान में संशोधित कर रहा है, लेकिन अभी तक लागू नहीं हुआ है। आप ** आसानी से ** एक से अधिक मेमोरी पूल कर सकते हैं। बेशक, वहाँ * सिंगलटन पैटर्न के लिए * वैध उपयोग हैं। लेकिन वे बेहद दुर्लभ हैं, और आपके द्वारा सूचीबद्ध किए गए लोग * उनमें से नहीं हैं। – jalf

संबंधित मुद्दे