C ++ में स्थिर कंस्ट्रक्टर? मुझे निजी स्थिर वस्तुओं को इनिशियलाइज़ करने की आवश्यकता है


176

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

मेरे बारे में यह सोचा जाता है कि चूँकि चर केवल पढ़े जा सकते हैं, वे केवल सार्वजनिक स्थैतिक हो सकते हैं, इसलिए मैं उन्हें कक्षा के बाहर एक बार सेट कर सकता हूं, लेकिन एक बार फिर यह एक बदसूरत हैक की तरह लगता है।

क्या कक्षा में निजी स्टैटिक डेटा सदस्य होना संभव है अगर मैं उन्हें उदाहरण निर्माता में इनिशियलाइज़ नहीं करना चाहता?



1
@CiroSantilli 新疆 ill ill ill 法轮功 is यह प्रश्न निजी स्थैतिक आदिम प्रकारों के निरंतर मूल्यों को निर्धारित नहीं करते हुए, निजी स्थिर वस्तुओं को आरंभ करने के लिए कोड चलाने पर केंद्रित है । उपाय अलग हैं।
गॉर्डन गुस्ताफसन

आह, मुझे लगता है कि आप सही हैं, पीछे हट रहे हैं।
सिरो सेंटिल्ली :56 冠状 iro 法轮功

जवाबों:


180

एक स्थिर रचनाकार के बराबर पाने के लिए, आपको स्थैतिक डेटा को रखने के लिए एक अलग साधारण वर्ग लिखने की आवश्यकता होती है और फिर उस साधारण वर्ग का एक स्थिर उदाहरण बनाते हैं।

class StaticStuff
{
     std::vector<char> letters_;

public:
     StaticStuff()
     {
         for (char c = 'a'; c <= 'z'; c++)
             letters_.push_back(c);
     }

     // provide some way to get at letters_
};

class Elsewhere
{
    static StaticStuff staticStuff; // constructor runs once, single instance

};

12
धन्यवाद! हालांकि यह सब करने के लिए बहुत कष्टप्रद है। कई "गलतियों" में से एक सी # और जावा से सीखा।
गॉर्डन गुस्ताफसन

109
हाँ। मैं हमेशा लोगों को इंगित करता हूं कि यदि C ++ ने उन सभी "गलतियों" को नहीं किया था, तो अन्य भाषाओं को उन्हें बनाना होगा। C ++ इतनी ज़मीन को कवर करती है, यहाँ तक कि गलतियाँ करना, इसके बाद आने वाली भाषाओं के लिए बहुत अच्छा रहा है।
क्वार्क

11
बस एक छोटी सी बारीकियों के रूप में, जब कोई स्थिर निर्माता के लिए कंस्ट्रक्टर निष्पादित करता है, तो निर्माता कोई भी गारंटी नहीं देते हैं। एक बहुचर्चित बहुत सुरक्षित दृष्टिकोण है क्लास एलीट {स्टैटिकस्टफ एंड गेट_स्टैटिकस्टफ () {स्टेटिक स्टैटिकस्टफ स्टैटिकस्टफ; // कंस्ट्रक्टर एक बार चलता है, जब किसी को पहली बार स्टैटिकस्टफ की आवश्यकता होती है; }}; मुझे आश्चर्य है कि अगर सी # और जावा में स्थिर कंस्ट्रक्टर ऊपर दिए गए कोड के समान गारंटी प्रदान कर सकते हैं ...
ओलेग ज़ाइलिन

13
@Oleg: हाँ वे करते हैं। सभी गैर स्थानीय चरों के लिए कंस्ट्रक्टरों को मुख्य प्रवेश करने से पहले निष्पादित किया जाता है। यह भी गारंटी देता है कि एक संकलन इकाई के भीतर निर्माण के क्रम को अच्छी तरह से परिभाषित किया गया है और संकलन इकाई के भीतर घोषणा के समान आदेश है। दुर्भाग्य से वे कई संकलन इकाइयों के क्रम को परिभाषित नहीं करते हैं।
मार्टिन

13
यह वास्तव में एक ऐसा मामला है जहां friendबहुत कुछ समझ में आता है ताकि वर्ग Elsewhereआसानी से StaticStuffइंटर्नल तक पहुंच सके (किसी भी खतरनाक तरीके से एनकैप्सुलेशन को तोड़ने के बिना, मैं जोड़ सकता हूं)।
कोनराड रुडोल्फ

81

वैसे आपके पास हो सकता है

class MyClass
{
    public:
        static vector<char> a;

        static class _init
        {
          public:
            _init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
        } _initializer;
};

इसे (.cpp में) न भूलें:

vector<char> MyClass::a;
MyClass::_init MyClass::_initializer;

कार्यक्रम अभी भी दूसरी पंक्ति के बिना लिंक करेगा, लेकिन इनिशियलाइज़र को निष्पादित नहीं किया जाएगा।


+1 (इसे आज़माकर न देखें) लेकिन: जब ctor _init._init () कहा जाता है? MyClass के ctor से पहले या बाद में जब मेरे पास एक स्थिर MyClass ऑब्जेक्ट होता है? मुझे लगता है कि आप बता नहीं सकते ...
उर।

2
हैलो, मुझे इस "इनिशियलज़र" जादू के बारे में और कहाँ मिल सकता है?
करेल बिलेक

MyClass::a.push_back(i)इसके बजाय नहीं होना चाहिए a.push_back(i)?
नील बसु

4
@ हमारा .: _initializerका एक उप-विषय है MyClass। इस क्रम में Subobjects की शुरुआत की जाती है: वर्चुअल बेस क्लास सब -जेक्ट्स, डेप्थ-फर्स्ट में, लेफ्ट-टू-राइट ऑर्डर (लेकिन केवल एक बार प्रत्येक अलग-अलग सबबॉजेक्ट को इनिशियलाइज़ करते हुए); फिर सादा बेस क्लास सब -जेक्ट, गहराई-पहले, बाएं से दाएं क्रम में; तब सदस्य घोषणा के क्रम में अवज्ञा करता है। इसलिए यह EFraim की रणनीति का उपयोग करने के लिए सुरक्षित है, बशर्ते कि यह कोड _initialiserकेवल इससे पहले घोषित किए गए सदस्यों को संदर्भित करता है।
j_random_hacker 2

2
यह उत्तर स्वीकार किए गए से बेहतर है क्योंकि लेखक ने दूसरे कोड क्लिप पर अपरिहार्य प्रारंभिक का उल्लेख किया था।
जेफ टी।

33

सी ++ 11 समाधान

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

शीर्ष लेख फ़ाइल:

class MyClass {
    static const vector<char> letters;
    static const size_t letterCount;
};

मूल फाइल:

// Initialize MyClass::letters by using a lambda expression.
const vector<char> MyClass::letters = [] {
    vector<char> letters;
    for (char c = 'a'; c <= 'z'; c++)
        letters.push_back(c);
    return letters;
}();

// The initialization order of static members is defined by the order of
// definition within the source file, so we can access MyClass::letters here.
const size_t MyClass::letterCount = letters.size();

दिलचस्प समाधान। इस मामले में अगर मैं एक अपवाद फेंक दूं तो कौन इसे पकड़ सकता है?
रफ़ी वीनर

5
स्टेटिक प्रोग्राम इनिशियलाइज़ेशन कोड को कभी भी कोई अपवाद नहीं फेंकना चाहिए , या प्रोग्राम क्रैश हो जाएगा। यदि आप try catchअपवादों को फेंक सकते हैं, तो आपको इनिशलाइज़र लॉजिक को एक ब्लॉक में लपेटना होगा ।
emkey08

19

.H फ़ाइल में:

class MyClass {
private:
    static int myValue;
};

.Cpp फ़ाइल में:

#include "myclass.h"

int MyClass::myValue = 0;

5
यह व्यक्तिगत स्थिर सदस्यों (प्रकार की परवाह किए बिना) के लिए ठीक काम करता है। स्थिर निर्माणकर्ताओं की तुलना में कमी यह है कि आप विभिन्न स्थैतिक सदस्यों के बीच एक आदेश लागू नहीं कर सकते । यदि आपको ऐसा करने की आवश्यकता है, तो इयरविकर का उत्तर देखें।
क्वार्क

मैं ठीक यही कर रहा हूं, लेकिन यह अभी भी संकलित नहीं है। और यह कहता है कि यह समस्या क्षेत्र है (निर्माणकर्ता में, हेडर नहीं)
Flotolk

14

यहां डैनियल ईयरविकर के समान एक और दृष्टिकोण है, जो कोनराड रूडोल्फ के मित्र वर्ग के सुझाव का उपयोग भी करता है। यहां हम आपके मुख्य वर्ग के स्थिर सदस्यों को आरंभ करने के लिए एक आंतरिक निजी मित्र उपयोगिता वर्ग का उपयोग करते हैं। उदाहरण के लिए:

शीर्ष लेख फ़ाइल:

class ToBeInitialized
{
    // Inner friend utility class to initialize whatever you need

    class Initializer
    {
    public:
        Initializer();
    };

    friend class Initializer;

    // Static member variables of ToBeInitialized class

    static const int numberOfFloats;
    static float *theFloats;

    // Static instance of Initializer
    //   When this is created, its constructor initializes
    //   the ToBeInitialized class' static variables

    static Initializer initializer;
};

कार्यान्वयन फ़ाइल:

// Normal static scalar initializer
const int ToBeInitialized::numberOfFloats = 17;

// Constructor of Initializer class.
//    Here is where you can initialize any static members
//    of the enclosing ToBeInitialized class since this inner
//    class is a friend of it.

ToBeInitialized::Initializer::Initializer()
{
    ToBeInitialized::theFloats =
        (float *)malloc(ToBeInitialized::numberOfFloats * sizeof(float));

    for (int i = 0; i < ToBeInitialized::numberOfFloats; ++i)
        ToBeInitialized::theFloats[i] = calculateSomeFancyValue(i);
}

इस दृष्टिकोण का बाहरी दुनिया से शुरुआती वर्ग को पूरी तरह से छिपाने का लाभ है, वर्ग के भीतर मौजूद सभी चीजों को प्रारंभिक रखा जा सकता है।


+1 एक उदाहरण देने के लिए जो कार्यान्वयन को अपनी फ़ाइल में रखता है।
एंड्रयू लार्सन

1
इसके अलावा, आपको यह सुनिश्चित करना होगा कि क्या ToBeInitialized::Initializer::Initializer()कहा जाता है, इसलिए आपको ToBeInitialized::Initializer ToBeInitialized::initializer;कार्यान्वयन फ़ाइल में जोड़ना होगा। मैंने आपके विचार से और एफ्रैम के विचार से कुछ चीजें लीं, और यह ठीक उसी तरह काम करता है जैसा मुझे इसकी आवश्यकता है और यह साफ दिखता है। धन्यवाद दोस्त।
एंड्रयू लार्सन

11

Test::StaticTest() वैश्विक स्थैतिक आरंभ के दौरान एक बार कहा जाता है।

कॉलर को केवल उस फ़ंक्शन को एक पंक्ति जोड़ना होगा जो उनका स्टैटिक कंस्ट्रक्टर हो।

static_constructor<&Test::StaticTest>::c;cवैश्विक स्थैतिक आरंभ के दौरान आरंभीकरण को बल देता है ।

template<void(*ctor)()>
struct static_constructor
{
    struct constructor { constructor() { ctor(); } };
    static constructor c;
};

template<void(*ctor)()>
typename static_constructor<ctor>::constructor static_constructor<ctor>::c;

/////////////////////////////

struct Test
{
    static int number;

    static void StaticTest()
    {
        static_constructor<&Test::StaticTest>::c;

        number = 123;
        cout << "static ctor" << endl;
    }
};

int Test::number;

int main(int argc, char *argv[])
{
    cout << Test::number << endl;
    return 0;
}

यह एक शानदार उपाय है। मुझे वास्तव में डगलस मंडेल का जवाब पसंद है , लेकिन यह और भी अधिक संक्षिप्त है।
FlintZA

यह वास्तव में आश्चर्यजनक है!
nh_

9

एक init()समारोह के लिए कोई ज़रूरत नहीं है , std::vectorएक सीमा से बनाया जा सकता है:

// h file:
class MyClass {
    static std::vector<char> alphabet;
// ...
};

// cpp file:
#include <boost/range.hpp>
static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
std::vector<char> MyClass::alphabet( boost::begin( ::alphabet ), boost::end( ::alphabet ) );

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

C ++ 11 अद्यतन

C ++ 11 के अनुसार, आप इसके बजाय ऐसा कर सकते हैं:

// cpp file:
std::vector<char> MyClass::alphabet = { 'a', 'b', 'c', ..., 'z' };

यह मूल उत्तर में C ++ 98 समाधान के समान शब्दार्थ है, लेकिन आप दाहिने हाथ की ओर एक स्ट्रिंग शाब्दिक का उपयोग नहीं कर सकते हैं, इसलिए यह पूरी तरह से श्रेष्ठ नहीं है। हालांकि, अगर आप किसी भी अन्य प्रकार का एक वेक्टर की तुलना में char, wchar_t, char16_tया char32_t(सरणियों जिनमें से स्ट्रिंग शाब्दिक रूप में लिखा जा सकता है), सी ++ 11 संस्करण सख्ती से अन्य वाक्य रचना शुरू करने के बिना बॉयलरप्लेट कोड निकाल देंगे, सी ++ 98 की तुलना में संस्करण।


मुझें यह पसंद है। हालांकि अगर केवल हम इसे अब बेकार वर्णमाला के बिना एक पंक्ति में कर सकते हैं।
मार्टिन यॉर्क

पुस्तकालयों के साथ समस्याएं पैदा करने के लिए, क्या यह बात मायने रखती है कि क्या स्थिर वर्ग निजी या सार्वजनिक है? इसके अतिरिक्त, यदि लाइब्रेरी स्थिर (.a) या डायनेमिक (.so) है तो क्या इससे कोई फर्क पड़ता है?
ज़ाक्रि क्रुस

@ZacharyKraus: सार्वजनिक / निजी वर्ग क्या है? और नहीं, जबकि समस्याएं अलग-अलग हैं, लेकिन अतिव्यापी है, इससे कोई फर्क नहीं पड़ता कि पुस्तकालय सांख्यिकीय रूप से या गतिशील रूप से जुड़ा हुआ है।
मार्क मुत्ज़ - mmutz

@ MarcMutz-mmutz सार्वजनिक / निजी वर्ग का उपयोग करने के बारे में क्षमा करें जो C ++ शब्दावली सही नहीं है। मैं जिस बात का जिक्र कर रहा था, वह ऊपर के ईफ्रिम द्वारा हल है। हालांकि मेरे संस्करण में, मैंने स्थिर वर्ग के सदस्य को निजी बना दिया। मैं यह समझने की कोशिश कर रहा था कि सार्वजनिक या निजी के रूप में एक स्थिर वर्ग के सदस्य होने से पुस्तकालय विकास और प्रयोज्य में अंतर होता है। मेरी आंत बताती है कि यह पुस्तकालय को प्रभावित नहीं करना चाहिए क्योंकि उपयोगकर्ताओं के पास कभी भी स्थिर वर्ग के सदस्य या उसके भवन तक पहुंच नहीं होगी, लेकिन मुझे इस विषय पर कुछ गुरु का ज्ञान प्राप्त करना अच्छा लगेगा।
ज़ाचरी क्रूस

@ZacharyKraus: डायनामिक्स की मुख्य समस्या जिसमें डायनामिक इनिशियलाइज़ेशन की आवश्यकता होती है ([basic.start.init] / 2) यह है कि वे कोड चलाते हैं। पुस्तकालयों में, यह हो सकता है कि विध्वंसक चलाए जाने पर पुस्तकालय कोड पहले से ही अनलोड किया गया हो। यदि आप अधिक सुनना चाहते हैं, तो मैं इसके बारे में एक प्रश्न पोस्ट करने का सुझाव देता हूं।
मार्क मुत्ज़ -

6

C ++ में समस्याओं से सीख लेने के बाद, स्थिर कंस्ट्रक्टर्स की अवधारणा जावा में शुरू की गई थी। इसलिए हमारे पास कोई प्रत्यक्ष समकक्ष नहीं है।

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

//header

class A
{
    // Make sure this is private so that nobody can missues the fact that
    // you are overriding std::vector. Just doing it here as a quicky example
    // don't take it as a recomendation for deriving from vector.
    class MyInitedVar: public std::vector<char>
    {
        public:
        MyInitedVar()
        {
           // Pre-Initialize the vector.
           for(char c = 'a';c <= 'z';++c)
           {
               push_back(c);
           }
        }
    };
    static int          count;
    static MyInitedVar  var1;

};


//source
int            A::count = 0;
A::MyInitedVar A::var1;

4

जब मैं कक्षा की तैयारी और उपयोग करने की कोशिश कर रहा हूँ Elsewhere( अर्वाचीन के उत्तर से ):

error LNK2001: unresolved external symbol "private: static class StaticStuff Elsewhere::staticStuff" (?staticStuff@Elsewhere@@0VStaticStuff@@A)

ऐसा लगता है कि वर्ग परिभाषा (CPP) के बाहर कुछ कोड डाले बिना गैर-पूर्णांक प्रकारों की स्थिर विशेषताओं को शुरू करना संभव नहीं है।

उस संकलन को बनाने के लिए आप इसके बजाय " एक स्थिर स्थानीय चर के साथ एक स्थिर विधि " का उपयोग कर सकते हैं । कुछ इस तरह:

class Elsewhere
{
public:
    static StaticStuff& GetStaticStuff()
    {
        static StaticStuff staticStuff; // constructor runs once, single instance
        return staticStuff;
    }
};

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

ह्यूगो गोंजालेज कास्त्रो।


हालांकि थ्रेड्स का उपयोग करते समय सावधान रहें। मेरा मानना ​​है कि जीसीसी में स्थैतिक स्थानीय लोगों का निर्माण समवर्ती निष्पादन के खिलाफ संरक्षित है, लेकिन विज़ुअल सी ++ में ऐसा नहीं है।
डैनियल ईयरविकर

1
C ++ से 11 के बाद से, और POSIX में, यह है धागे की सुरक्षित किया जाना है।
मार्क मुत्ज़ - mmutz

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

बहुत बढ़िया! यह इसे पूरा करता है।
गाबे हेल्समर

4

मुझे लगता है कि इसका सरल समाधान होगा:

    //X.h
    #pragma once
    class X
    {
    public:
            X(void);
            ~X(void);
    private:
            static bool IsInit;
            static bool Init();
    };

    //X.cpp
    #include "X.h"
    #include <iostream>

    X::X(void)
    {
    }


    X::~X(void)
    {
    }

    bool X::IsInit(Init());
    bool X::Init()
    {
            std::cout<< "ddddd";
            return true;
    }

    // main.cpp
    #include "X.h"
    int main ()
    {
            return 0;
    }

यह है कि मैं यह भी कैसे करते हैं।
ईथरेल

1

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

यहाँ अंतिम कोड है:

मैंने सरलीकृत कोड और रैंड () फ़ंक्शन और इसके सिंगल सीड इनिशियेटर सरैंड () का उपयोग किया

interface IRandClass
{
 public:
    virtual int GetRandom() = 0;
};

class RandClassSingleton
{
private:
  class RandClass : public IRandClass
  {
    public:
      RandClass()
      {
        srand(GetTickCount());
      };

     virtual int GetRandom(){return rand();};
  };

  RandClassSingleton(){};
  RandClassSingleton(const RandClassSingleton&);

  // static RandClass m_Instance;

  // If you declare m_Instance here you need to place
  // definition for this static object somewhere in your cpp code as
  // RandClassSingleton::RandClass RandClassSingleton::m_Instance;

  public:

  static RandClass& GetInstance()
  {
      // Much better to instantiate m_Instance here (inside of static function).
      // Instantiated only if this function is called.

      static RandClass m_Instance;
      return m_Instance;
  };
};

main()
{
    // Late binding. Calling RandClass ctor only now
    IRandClass *p = &RandClassSingleton::GetInstance();
    int randValue = p->GetRandom();
}
abc()
{
    IRandClass *same_p = &RandClassSingleton::GetInstance();
}

1

यहाँ EFraim के समाधान का मेरा संस्करण है; अंतर यह है कि, अंतर्निहित टेम्पलेट तात्कालिकता के लिए धन्यवाद, स्थिर निर्माता को केवल तभी कहा जाता है यदि वर्ग के उदाहरण बनाए जाते हैं, और यह कि .cppफ़ाइल में कोई परिभाषा की आवश्यकता नहीं है (टेम्पलेट तात्कालिकता के लिए धन्यवाद)।

में .hफ़ाइल, तुम हो:

template <typename Aux> class _MyClass
{
    public:
        static vector<char> a;
        _MyClass() {
            (void) _initializer; //Reference the static member to ensure that it is instantiated and its initializer is called.
        }
    private:
        static struct _init
        {
            _init() { for(char i='a'; i<='z'; i++) a.push_back(i); }
        } _initializer;

};
typedef _MyClass<void> MyClass;

template <typename Aux> vector<char> _MyClass<Aux>::a;
template <typename Aux> typename _MyClass<Aux>::_init _MyClass<Aux>::_initializer;

में .cppफ़ाइल, आप कर सकते हैं:

void foobar() {
    MyClass foo; // [1]

    for (vector<char>::iterator it = MyClass::a.begin(); it < MyClass::a.end(); ++it) {
        cout << *it;
    }
    cout << endl;
}

ध्यान दें कि MyClass::aयदि लाइन [1] है, तो केवल इसलिए इनिशियलाइज़ किया जाता है, क्योंकि कंस्ट्रक्टर को उस कॉल (और इंस्टेंटेशन की आवश्यकता होती है), जिसके लिए उसे तुरंत की आवश्यकता होती है _initializer


1

यहां एक अन्य विधि है, जहां वेक्टर उस फ़ाइल के लिए निजी है जिसमें एक अनाम नेमस्पेस का उपयोग करके कार्यान्वयन होता है। यह लुकअप टेबल जैसी चीजों के लिए उपयोगी है जो कार्यान्वयन के लिए निजी हैं:

#include <iostream>
#include <vector>
using namespace std;

namespace {
  vector<int> vec;

  struct I { I() {
    vec.push_back(1);
    vec.push_back(3);
    vec.push_back(5);
  }} i;
}

int main() {

  vector<int>::const_iterator end = vec.end();
  for (vector<int>::const_iterator i = vec.begin();
       i != end; ++i) {
    cout << *i << endl;
  }

  return 0;
}

यद्यपि आप नाम Iऔर iकुछ अधिक अस्पष्ट चाहते हैं, ताकि आप गलती से उन्हें फ़ाइल में कहीं कम उपयोग न करें।
जिम हंज़िकेर

1
सच कहूं तो, यह देखना मुश्किल है कि कार्यान्वयन फाइलों में कोई भी व्यक्ति नाम स्थान के बजाय निजी स्थिर सदस्यों का उपयोग क्यों करना चाहेगा।
जिम हुनजिकर

1

यह निश्चित रूप से वर्तमान में स्वीकृत जवाब (डैनियल ईयरविकर द्वारा) के रूप में जटिल होने की आवश्यकता नहीं है। वर्ग सतही है। इस मामले में भाषा युद्ध की कोई आवश्यकता नहीं है।

.hpp फ़ाइल:

vector<char> const & letters();

.cpp फ़ाइल:

vector<char> const & letters()
{
  static vector<char> v = {'a', 'b', 'c', ...};
  return v;
}


0

आप स्थैतिक सदस्य चर को उसी तरह परिभाषित करते हैं जिस तरह से आप सदस्य विधियों को परिभाषित करते हैं।

foo.h

class Foo
{
public:
    void bar();
private:
    static int count;
};

foo.cpp

#include "foo.h"

void Foo::bar()
{
    // method definition
}

int Foo::count = 0;

2
CrazyJugglerDrummer प्रश्न एक स्थैतिक सादे पुराने डेटा प्रकार के बारे में नहीं था :)
jww

0

एक स्थैतिक चर को इनिशियलाइज़ करने के लिए, आप बस एक सोर्स फाइल के अंदर ऐसा करते हैं। उदाहरण के लिए:

//Foo.h
class Foo
{
 private:
  static int hello;
};


//Foo.cpp
int Foo::hello = 1;

CrazyJugglerDrummer प्रश्न एक स्थैतिक सादे पुराने डेटा प्रकार के बारे में नहीं था :)
jww

0

C # के व्यवहार की नकल करने के लिए टेम्पलेट बनाने के बारे में।

template<class T> class StaticConstructor
{
    bool m_StaticsInitialised = false;

public:
    typedef void (*StaticCallback)(void);

    StaticConstructor(StaticCallback callback)
    {
        if (m_StaticsInitialised)
            return;

        callback();

        m_StaticsInitialised = true;
    }
}

template<class T> bool StaticConstructor<T>::m_StaticsInitialised;

class Test : public StaticConstructor<Test>
{
    static std::vector<char> letters_;

    static void _Test()
    {
        for (char c = 'a'; c <= 'z'; c++)
            letters_.push_back(c);
    }

public:
    Test() : StaticConstructor<Test>(&_Test)
    {
        // non static stuff
    };
};

0

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

#include <iostream>

class MyClass 
{

    static const char * const letters(void){
        static const char * const var = "abcdefghijklmnopqrstuvwxyz";
        return var;
    }

    public:
        void show(){
            std::cout << letters() << "\n";
        }
};


int main(){
    MyClass c;
    c.show();
}

0

क्या यह कोई समाधान है?

class Foo
{
public:
    size_t count;
    Foo()
    {
        static size_t count = 0;
        this->count = count += 1;
    }
};

0

एक स्थिर निर्माणकर्ता को नीचे के रूप में एक मित्र वर्ग या नेस्टेड वर्ग का उपयोग करके अनुकरण किया जा सकता है।

class ClassStatic{
private:
    static char *str;
public:
    char* get_str() { return str; }
    void set_str(char *s) { str = s; }
    // A nested class, which used as static constructor
    static class ClassInit{
    public:
        ClassInit(int size){ 
            // Static constructor definition
            str = new char[size];
            str = "How are you?";
        }
    } initializer;
};

// Static variable creation
char* ClassStatic::str; 
// Static constructor call
ClassStatic::ClassInit ClassStatic::initializer(20);

int main() {
    ClassStatic a;
    ClassStatic b;
    std::cout << "String in a: " << a.get_str() << std::endl;
    std::cout << "String in b: " << b.get_str() << std::endl;
    a.set_str("I am fine");
    std::cout << "String in a: " << a.get_str() << std::endl;
    std::cout << "String in b: " << b.get_str() << std::endl;
    std::cin.ignore();
}

आउटपुट:

String in a: How are you?
String in b: How are you?
String in a: I am fine
String in b: I am fine

आप newकेवल सूचक को तुरंत लीक करने और इसे अधिलेखित करने के लिए एक चार सरणी में क्यों कर रहे हैं !?
एरिक

0

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

std::call_once()C ++ 11 में उपलब्ध है; यदि आप इसका उपयोग नहीं कर सकते हैं, तो यह एक स्थिर बूलियन वर्ग-चर और एक तुलना-और-विनिमय परमाणु-संचालन के साथ किया जा सकता है। अपने निर्माता में, यदि आप atomically से वर्ग स्थैतिक झंडा बदल सकते हैं को देखने falseके लिए true, और यदि हां, तो आप स्थिर निर्माणाधीन कोड चला सकते हैं।

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

C ++ 11 की अनुपस्थिति में, यह आपको आरंभ करना चाहिए।

आपका मार्गदर्शन करने के लिए यहां कुछ छद्मकोश हैं। इसे अपनी कक्षा परिभाषा में रखें:

enum EStaticConstructor { kNotRun, kRunning, kDone };
static volatile EStaticConstructor sm_eClass = kNotRun;

और यह आपके निर्माता में है:

while (sm_eClass == kNotRun)
{
    if (atomic_compare_exchange_weak(&sm_eClass, kNotRun, kRunning))
    {
        /* Perform static initialization here. */

        atomic_thread_fence(memory_order_release);
        sm_eClass = kDone;
    }
}
while (sm_eClass != kDone)
    atomic_pause();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.