C++
संग्रहण वर्ग निर्दिष्ट करता है
खोज…
परिचय
स्टोरेज क्लास स्पेसिफिकर्स वे कीवर्ड होते हैं जिनका उपयोग घोषणाओं में किया जा सकता है। वे घोषणा के प्रकार को प्रभावित नहीं करते हैं, लेकिन आमतौर पर जिस तरह से इकाई संग्रहीत होती है, उसे संशोधित करते हैं।
टिप्पणियों
छह भंडारण वर्ग विनिर्देशक हैं, हालांकि सभी नहीं भाषा का एक ही संस्करण में: 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;
}
};
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
एक भंडारण वर्ग विनिर्देशक जब एक परिवर्तनशील लैम्ब्डा बनाने के लिए इस तरह से उपयोग नहीं किया है।
रजिस्टर करें
एक संग्रहण वर्ग निर्दिष्ट करता है कि संकलक को संकेत देता है कि एक चर का भारी उपयोग किया जाएगा। शब्द "रजिस्टर" इस तथ्य से संबंधित है कि एक कंपाइलर सीपीयू रजिस्टर में इस तरह के एक चर को चुनने के लिए चुन सकता है ताकि इसे कम घड़ी चक्रों में एक्सेस किया जा सके। इसे C ++ 11 में शुरू किया गया था।
register int i = 0;
while (i < 100) {
f(i);
int g = i*i;
i += h(i, g);
}
स्थानीय चर और फ़ंक्शन पैरामीटर दोनों को register
घोषित किया जा सकता है। सी के विपरीत, सी ++ एक register
चर के साथ क्या किया जा सकता है पर कोई प्रतिबंध नहीं रखता है। उदाहरण के लिए, यह एक register
चर का पता लेने के लिए वैध है, लेकिन यह संकलक को वास्तव में एक रजिस्टर में इस तरह के चर को संग्रहीत करने से रोक सकता है।
कीवर्ड register
अप्रयुक्त और आरक्षित है। एक प्रोग्राम जो कीवर्ड register
का उपयोग करता है, बीमार है।
स्थिर
static
भंडारण वर्ग विनिर्देशक के तीन अलग-अलग अर्थ हैं।
नेमस्पेस स्पेस पर घोषित एक वैरिएबल या फंक्शन को इंटरनल लिंकेज देता है।
// 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)); }
स्थिर भंडारण अवधि (जब तक कि यह
thread_local
) की एक चर घोषित करता है। नेमस्पेस-स्कोप वैरिएबल स्पष्ट रूप से स्थिर हैं। एक स्थिर स्थानीय चर को केवल एक बार आरंभिक किया जाता है, पहली बार नियंत्रण अपनी परिभाषा से गुजरता है, और हर बार इसका दायरा बाहर निकलने पर नष्ट नहीं होता है।void f() { static int count = 0; std::cout << "f has been called " << ++count << " times so far\n"; }
जब एक वर्ग के सदस्य की घोषणा पर लागू होता है, तो उस सदस्य को एक स्थिर सदस्य घोषित करता है।
struct S { static S* create() { return new S; } }; int main() { S* s = S::create(); }
ध्यान दें कि किसी वर्ग के स्थैतिक डेटा सदस्य के मामले में, 2 और 3 दोनों एक साथ लागू होते हैं: static
कीवर्ड दोनों सदस्य को एक स्थिर डेटा सदस्य बनाता है और इसे स्थिर भंडारण अवधि के साथ एक चर में बनाता है।
ऑटो
स्वचालित संग्रहण अवधि के लिए एक चर की घोषणा करता है। यह निरर्थक है, क्योंकि स्वचालित भंडारण अवधि पहले से ही ब्लॉक गुंजाइश पर डिफ़ॉल्ट है, और ऑटो स्पेसर को नाम स्थान के दायरे में अनुमति नहीं है।
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
संदर्भ के आधार पर निम्नलिखित तीन तरीकों में से एक में घोषणा को संशोधित कर सकता है:
इसका उपयोग एक चर को परिभाषित किए बिना घोषित करने के लिए किया जा सकता है। आमतौर पर, इसका उपयोग शीर्ष लेख में वैरिएबल फ़ाइल के लिए किया जाता है जिसे एक अलग कार्यान्वयन फ़ाइल में परिभाषित किया जाएगा।
// 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)
यह नेमस्पेस स्कोप पर एक वैरिएबल को बाहरी लिंकेज देता है, भले ही
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 }
यदि यह पहले लिंकेज के साथ घोषित किया गया था, तो यह ब्लॉक स्कोप पर एक चर 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
में बदल दिया गया, तो यह प्रोग्राम की शुद्धता या शब्दार्थ को बिल्कुल प्रभावित नहीं करेगा, लेकिन संभवतः कोड के रीडर को भ्रमित करेगा।