45

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

एक .cpp या .h फ़ाइल में यह कोई समस्या नहीं है: उदाहरण घोषित किए जाने वाले क्रम में बनाए जाएंगे। हालांकि, जब आप किसी अन्य संकलन इकाई में किसी उदाहरण के साथ एक स्थिर उदाहरण प्रारंभ करना चाहते हैं, तो ऑर्डर निर्दिष्ट करना असंभव प्रतीत होता है। नतीजा यह है कि, मौसम के आधार पर, ऐसा हो सकता है कि एक दूसरे पर निर्भर उदाहरण बनाया गया है, और इसके बाद ही अन्य उदाहरण का निर्माण किया गया है। नतीजा यह है कि पहला उदाहरण गलत तरीके से शुरू किया गया है।

क्या कोई यह जानता है कि स्थिर ऑब्जेक्ट सही क्रम में बनाए गए हैं या नहीं? मैंने समाधान के लिए लंबे समय से खोज की है, उन सभी को कोशिश कर रहा है (श्वार्ज़ काउंटर समाधान सहित), लेकिन मुझे संदेह है कि वास्तव में काम करता है।

Type& globalObject() 
{ 
    static Type theOneAndOnlyInstance; 
    return theOneAndOnlyInstance; 
} 

दरअसल, इस काम करता है:

एक संभावना यह स्थिर समारोह के सदस्य के साथ चाल है। अफसोस की बात है, आपको GlobalObject()। GlobalFbction() के बजाय globalObject() सदस्य फ़ंक्शन() लिखना है, जिसके परिणामस्वरूप कुछ भ्रमित और सुरुचिपूर्ण क्लाइंट कोड होता है।

अद्यतन: आपकी प्रतिक्रियाओं के लिए धन्यवाद। अफसोस की बात है, ऐसा लगता है कि मैंने अपने स्वयं के प्रश्न का उत्तर दिया है। मुझे लगता है मुझे इसके साथ रहने के लिए सीखना होगा ...

+0

_The उदाहरणों क्रम में वे are_ में बनाया जाएगा ** परिभाषित ** –

उत्तर

50

आपने अपने प्रश्न का उत्तर दिया है। स्टेटिक प्रारंभिक क्रम अपरिभाषित है, और इसके आस-पास का सबसे सुरुचिपूर्ण तरीका है (जबकि स्थिर स्थिरता अभी भी कर रहा है यानी इसे पूरी तरह से पुन: सक्रिय नहीं कर रहा है) एक समारोह में प्रारंभिकता को लपेटना है।

से https://isocpp.org/wiki/faq/ctors#static-init-order

+6

लेकिन अफसोस, कि समाधान थ्रेड-सुरक्षित नहीं है। –

+0

@ चार्ल्स साल्विया आपको समय में 2.5 साल वापस ला रहा है :), क्या यह वास्तव में एक समस्या है कि यह थ्रेड-सुरक्षित नहीं है? हम स्थैतिक प्रारंभिकरण के बारे में बात कर रहे हैं, इसलिए, यह सब मुख्य() 'से पहले हो रहा है। क्या हमें वास्तव में 'मुख्य()' से पहले थ्रेड सुरक्षा मुद्दों के बारे में चिंतित होना चाहिए? – enobayram

+1

मुख्य प्रविष्टि से पहले नहीं, लेकिन जब विधि को पहली बार बुलाया जाता है। http://blogs.msdn.com/b/oldnewthing/archive/2004/03/08/85901.aspx –

7

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

लेकिन आप सही हैं, प्रारंभिकरण का एक विशेष क्रम सुनिश्चित करने का कोई तरीका नहीं है, और इसलिए यदि आपका दिल उस पर सेट है, तो आपके द्वारा वर्णित एक समारोह में प्रारंभिकता को ध्यान में रखते हुए, शायद सबसे आसान तरीका है।

+3

आप सही हैं, बहुत अधिक वैश्विक स्थैतिक चर का उपयोग करना मूर्ख नहीं है, लेकिन कुछ मामलों के लिए यह एक ही वस्तु को अत्यधिक आसपास से पार करने से बचाता है। लॉगर ऑब्जेक्ट के बारे में सोचें, लगातार चर के लिए कंटेनर, सभी आईपीसी कनेक्शनों का संग्रह, आदि ... –

+2

"ऑब्जेक्ट को अत्यधिक पास करने से बचें" यह कहने का एक तरीका है, "मेरे कार्यक्रम के घटकों के बीच निर्भरता इतनी व्यापक है जो उन्हें ट्रैक करना अत्यधिक काम है। इसलिए उन्हें ट्रैक करना बंद करना बेहतर है "। सिवाय इसके कि आमतौर पर यह बेहतर नहीं होता है - यदि निर्भरता को सरल नहीं किया जा सकता है तो वह तब होता है जब ऑब्जेक्ट पास हो जाता है, उसके बाद यह * ट्रैक * करने में सक्षम होता है। –

5

दरअसल, यह काम करता है। अफसोस की बात है, आपको GlobalObject()। GlobalFbction() के बजाय globalObject() सदस्य फ़ंक्शन() लिखना है, जिसके परिणामस्वरूप कुछ भ्रमित और सुरुचिपूर्ण क्लाइंट कोड होता है।

लेकिन सबसे महत्वपूर्ण बात यह है कि यह काम करता है, और यह विफलता प्रमाण है, यानी। सही उपयोग को बाईपास करना आसान नहीं है।

कार्यक्रम शुद्धता आपकी पहली प्राथमिकता होनी चाहिए। इसके अलावा, आईएमएचओ,() ऊपर पूरी तरह स्टाइलिस्ट है - यानी। पूरी तरह से महत्वहीन।

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

Globals & getGlobals() 
{ 
    static Globals cache; 
    return cache; 
} 

के लिए अपने कार्यक्रम में सभी वैश्विक वस्तुओं के लिए साफ करने के लिए में ~ वैश्विक() करने के लिए केवल एक कॉल नहीं है।

getGlobals().configuration.memberFunction(); 

तुम सच में चाहते थे आप मैक्रो का उपयोग टाइपिंग का एक छोटा सा बचाने के लिए एक मैक्रो में इस लपेट सकता है: एक वैश्विक आप अभी भी तरह कुछ है पर पहुंचने के लिए

#define GLOBAL(X) getGlobals().#X 
GLOBAL(object).memberFunction(); 

हालांकि, यह आपके प्रारंभिक समाधान पर सिर्फ वाक्य रचनात्मक चीनी है।

2

अधिकांश कंपाइलर (लिंकर्स) वास्तव में आदेश निर्दिष्ट करने के एक (गैर-पोर्टेबल) तरीके का समर्थन करते हैं। उदाहरण के लिए, दृश्य स्टूडियो के साथ आप कई अलग-अलग समूहों में प्रारंभिक व्यवस्था की व्यवस्था करने के लिए init_seg प्रज्ञा का उपयोग कर सकते हैं। AFAIK प्रत्येक समूह के भीतर आदेश की गारंटी देने का कोई तरीका नहीं है। चूंकि यह गैर-पोर्टेबल है, इसलिए आप यह विचार करना चाहेंगे कि क्या आप अपने डिज़ाइन को ठीक करने के लिए ठीक कर सकते हैं, लेकिन विकल्प वहां मौजूद है।

2

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

class Math { 
public: 
    static const float Pi() { 
     static const float s_PI = 3.14f; 
     return s_PI; 
    } 
} 

s_PI पहली बार प्रारंभ हो जाएगा पाई() विधि है आह्वान (जीसीसी में)। सावधान रहें: स्थैतिक भंडारण वाले स्थानीय वस्तुओं में एक कार्यान्वयन निर्भर जीवनशैली है, आगे के विवरण के लिए 2 में 6.7.4 की जांच करें।

Static keyword, C++ Standard

+2

यह अलग-अलग कैसे है, ओपी का दृष्टिकोण, सिवाय इसके कि आपने समारोह को कक्षा का सदस्य बनाया है? – einpoklum

+0

भी एक रोशनीपूर्ण उदाहरण नहीं है, क्योंकि ऐसा कोई ऑब्जेक्ट 'constexpr' –

0

एक विधि क्रम समस्या ठीक हो जाएगी में स्थिर रैपिंग, लेकिन यह सुरक्षित थ्रेड नहीं है के रूप में अन्य लोगों ने बताया है, लेकिन आप यह कर सकते हैं भी है कि यदि एक चिंता का विषय है यह धागा बनाने के लिए ।

// File scope static pointer is thread safe and is initialized first. 
static Type * theOneAndOnlyInstance = 0; 

Type& globalObject() 
{ 
    if(theOneAndOnlyInstance == 0) 
    { 
     // Put mutex lock here for thread safety 
     theOneAndOnlyInstance = new Type(); 
    } 

    return *theOneAndOnlyInstance; 
} 
+0

होना चाहिए और शीर्ष उत्तर वास्तव में यह सुझाव देता है, और लगभग 5 साल पहले इसका उत्तर दिया गया था। शायद हमें इसे एक उदाहरण के रूप में शीर्ष उत्तर में ले जाना चाहिए। – AndyG

+1

यह सी ++ 11 में कोई समस्या नहीं है। Http://stackoverflow.com/questions/8102125/is-local-static-variable-initialization-thread-safe-in-c11 देखें – povman

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