खोज…


परिचय

स्टोरेज क्लास स्पेसिफिकर्स वे कीवर्ड होते हैं जिनका उपयोग घोषणाओं में किया जा सकता है। वे घोषणा के प्रकार को प्रभावित नहीं करते हैं, लेकिन आमतौर पर जिस तरह से इकाई संग्रहीत होती है, उसे संशोधित करते हैं।

टिप्पणियों

छह भंडारण वर्ग विनिर्देशक हैं, हालांकि सभी नहीं भाषा का एक ही संस्करण में: auto (सी ++ जब तक 11), register (जब तक सी ++ 17), static , thread_local (के बाद से सी ++ 11), extern , और mutable

मानक के अनुसार,

सबसे एक भंडारण-वर्ग-विनिर्देशक में एक दिया डीईसीएल-विनिर्देशक-सेक में प्रदर्शित करेगा, सिवाय इसके कि thread_local साथ दिखाई दे सकते हैं static या extern

एक घोषणा में कोई भंडारण वर्ग निर्दिष्ट नहीं हो सकता है। उस स्थिति में, भाषा एक डिफ़ॉल्ट व्यवहार निर्दिष्ट करती है। उदाहरण के लिए, डिफ़ॉल्ट रूप से, ब्लॉक स्कोप पर घोषित एक वैरिएबल में स्वत: भंडारण अवधि होती है।

परिवर्तनशील

एक विशिष्ट वर्ग के गैर-स्थैतिक, गैर-संदर्भ डेटा सदस्य की घोषणा पर लागू किया जा सकता है। एक वर्ग का एक परिवर्तनशील सदस्य नहीं है const भी जब वस्तु है const

class C {
    int x;
    mutable int times_accessed;
  public:
    C(): x(0), times_accessed(0) {
    }
    int get_x() const {
        ++times_accessed; // ok: const member function can modify mutable data member
        return x;
    }
    void set_x(int x) {
        ++times_accessed;
        this->x = x;
    }
};
सी ++ 11

mutable लिए एक दूसरा अर्थ C ++ 11 में जोड़ा गया था। जब यह लैम्बडा के पैरामीटर सूची का अनुसरण करता है, तो यह लैम्बडा के फंक्शन कॉल ऑपरेटर पर निहित const को दबा देता है। इसलिए, एक उत्परिवर्तित लैम्ब्डा प्रतिलिपि द्वारा कैप्चर की गई संस्थाओं के मूल्यों को संशोधित कर सकता है। अधिक विवरण के लिए उत्परिवर्तित मेमने देखें।

std::vector<int> my_iota(int start, int count) {
    std::vector<int> result(count);
    std::generate(result.begin(), result.end(),
                  [start]() mutable { return start++; });
    return result;
}

ध्यान दें कि mutable एक भंडारण वर्ग विनिर्देशक जब एक परिवर्तनशील लैम्ब्डा बनाने के लिए इस तरह से उपयोग नहीं किया है।

रजिस्टर करें

सी ++ 17

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

register int i = 0;
while (i < 100) {
    f(i);
    int g = i*i;
    i += h(i, g);
}

स्थानीय चर और फ़ंक्शन पैरामीटर दोनों को register घोषित किया जा सकता है। सी के विपरीत, सी ++ एक register चर के साथ क्या किया जा सकता है पर कोई प्रतिबंध नहीं रखता है। उदाहरण के लिए, यह एक register चर का पता लेने के लिए वैध है, लेकिन यह संकलक को वास्तव में एक रजिस्टर में इस तरह के चर को संग्रहीत करने से रोक सकता है।

सी ++ 17

कीवर्ड register अप्रयुक्त और आरक्षित है। एक प्रोग्राम जो कीवर्ड register का उपयोग करता है, बीमार है।

स्थिर

static भंडारण वर्ग विनिर्देशक के तीन अलग-अलग अर्थ हैं।

  1. नेमस्पेस स्‍पेस पर घोषित एक वैरिएबल या फंक्‍शन को इंटरनल लिंकेज देता है।

    // internal function; can't be linked to
    static double semiperimeter(double a, double b, double c) {
        return (a + b + c)/2.0;
    }
    // exported to client
    double area(double a, double b, double c) {
        const double s = semiperimeter(a, b, c);
        return sqrt(s*(s-a)*(s-b)*(s-c));
    }
    
  2. स्थिर भंडारण अवधि (जब तक कि यह thread_local ) की एक चर घोषित करता है। नेमस्पेस-स्कोप वैरिएबल स्पष्ट रूप से स्थिर हैं। एक स्थिर स्थानीय चर को केवल एक बार आरंभिक किया जाता है, पहली बार नियंत्रण अपनी परिभाषा से गुजरता है, और हर बार इसका दायरा बाहर निकलने पर नष्ट नहीं होता है।

    void f() {
        static int count = 0;
        std::cout << "f has been called " << ++count << " times so far\n";
    }
    
  3. जब एक वर्ग के सदस्य की घोषणा पर लागू होता है, तो उस सदस्य को एक स्थिर सदस्य घोषित करता है।

    struct S {
        static S* create() {
            return new S;
        }
    };
    int main() {
        S* s = S::create();
    }
    

ध्यान दें कि किसी वर्ग के स्थैतिक डेटा सदस्य के मामले में, 2 और 3 दोनों एक साथ लागू होते हैं: static कीवर्ड दोनों सदस्य को एक स्थिर डेटा सदस्य बनाता है और इसे स्थिर भंडारण अवधि के साथ एक चर में बनाता है।

ऑटो

सी ++ 03

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

void f() {
    auto int x; // equivalent to: int x;
    auto y;     // illegal in C++; legal in C89
}
auto int z;     // illegal: namespace-scope variable cannot be automatic

C ++ 11 में, auto ने पूरी तरह से अर्थ बदल दिया, और अब भंडारण वर्ग निर्दिष्ट नहीं है, लेकिन इसके बजाय टाइप कटौती के लिए उपयोग किया जाता है।

निर्वासन

extern स्टोरेज क्लास extern संदर्भ के आधार पर निम्नलिखित तीन तरीकों में से एक में घोषणा को संशोधित कर सकता है:

  1. इसका उपयोग एक चर को परिभाषित किए बिना घोषित करने के लिए किया जा सकता है। आमतौर पर, इसका उपयोग शीर्ष लेख में वैरिएबल फ़ाइल के लिए किया जाता है जिसे एक अलग कार्यान्वयन फ़ाइल में परिभाषित किया जाएगा।

    // global scope
    int x;             // definition; x will be default-initialized
    extern int y;      // declaration; y is defined elsewhere, most likely another TU
    extern int z = 42; // definition; "extern" has no effect here (compiler may warn)
    
  2. यह नेमस्पेस स्कोप पर एक वैरिएबल को बाहरी लिंकेज देता है, भले ही const या constexpr ने अन्यथा आंतरिक लिंकेज का कारण बना हो।

    // global scope
    const int w = 42;            // internal linkage in C++; external linkage in C
    static const int x = 42;     // internal linkage in both C++ and C
    extern const int y = 42;     // external linkage in both C++ and C
    namespace {
        extern const int z = 42; // however, this has internal linkage since
                                 // it's in an unnamed namespace
    }
    
  3. यदि यह पहले लिंकेज के साथ घोषित किया गया था, तो यह ब्लॉक स्कोप पर एक चर redeclares। अन्यथा, यह लिंकेज के साथ एक नया चर घोषित करता है, जो निकटतम संलग्न नामस्थान का सदस्य है।

    // global scope
    namespace {
        int x = 1;
        struct C {
            int x = 2;
            void f() {
                extern int x;           // redeclares namespace-scope x
                std::cout << x << '\n'; // therefore, this prints 1, not 2
            }
        };
    }
    void g() {
        extern int y; // y has external linkage; refers to global y defined elsewhere
    }
    

एक फ़ंक्शन को भी extern घोषित किया जा सकता है, लेकिन इसका कोई प्रभाव नहीं है। यह आमतौर पर पाठक को संकेत के रूप में उपयोग किया जाता है कि यहां घोषित एक फ़ंक्शन किसी अन्य अनुवाद इकाई में परिभाषित किया गया है। उदाहरण के लिए:

 void f();        // typically a forward declaration; f defined later in this TU
 extern void g(); // typically not a forward declaration; g defined in another TU

उपरोक्त कोड में, अगर f को extern और g से नॉन- extern में बदल दिया गया, तो यह प्रोग्राम की शुद्धता या शब्दार्थ को बिल्कुल प्रभावित नहीं करेगा, लेकिन संभवतः कोड के रीडर को भ्रमित करेगा।



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow