क्या एक अप्रयुक्त सदस्य चर स्मृति लेता है?


91

क्या एक सदस्य चर को आरंभीकृत करना और संदर्भित नहीं करना / इसका उपयोग करना आगे चलकर RAM को रनटाइम के दौरान लेता है, या संकलक केवल उस चर को अनदेखा करता है?

struct Foo {
    int var1;
    int var2;

    Foo() { var1 = 5; std::cout << var1; }
};

ऊपर के उदाहरण में, सदस्य 'var1' को एक मान मिलता है जिसे बाद में कंसोल में प्रदर्शित किया जाता है। हालांकि, 'Var2' का उपयोग बिल्कुल नहीं किया जाता है। इसलिए रनटाइम के दौरान इसे मेमोरी में लिखना संसाधनों की बर्बादी होगी। क्या कंपाइलर इस प्रकार की स्थितियों को एक खाते में लेता है और केवल अप्रयुक्त चर को अनदेखा करता है, या क्या फू वस्तु हमेशा एक ही आकार की होती है, चाहे उसके सदस्यों का उपयोग किया जाए?


25
यह संकलक, वास्तुकला, ऑपरेटिंग सिस्टम और उपयोग किए गए अनुकूलन पर निर्भर करता है।
उल्लू

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

2
@ और वे वास्तव में कुछ भी नहीं कर रहे हैं क्योंकि निम्न डेटा सदस्यों के पते का मूल्यांकन किया जाता है। इसका मतलब यह है कि उन गद्दी सदस्यों के अस्तित्व का कार्यक्रम पर एक चौकस व्यवहार है। यहाँ, var2नहीं है।
YSC

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

2
@geza sizeof(Foo)परिभाषा से कम नहीं हो सकता है - यदि आप sizeof(Foo)इसे प्रिंट करते हैं तो इसे 8(सामान्य प्लेटफार्मों पर) उपज चाहिए । संकलक किसी भी संदर्भ में एलटीओ या पूरे कार्यक्रम के अनुकूलन के बिना, किसी भी संदर्भ में (किसी भी चीज के माध्यम से या स्टैक पर या फ़ंक्शन कॉल में ...) द्वारा उपयोग किए गए स्थान को अनुकूलित कर सकते हैं । जहां यह संभव नहीं है वे ऐसा नहीं करेंगे, जैसा कि किसी अन्य अनुकूलन के बारे में है। मेरा मानना ​​है कि स्वीकृत उत्तर को संपादित करने से इसे गुमराह होने की संभावना काफी कम हो जाती है। var2new
मैक्स लैंगहॉफ

जवाबों:


106

सुनहरा C ++ "as-if" नियम 1 में कहा गया है कि, यदि प्रोग्राम का अवलोकनीय व्यवहार अप्रयुक्त डेटा-सदस्य अस्तित्व पर निर्भर नहीं करता है, तो संकलक को इसे अनुकूलित करने की अनुमति है

क्या एक अप्रयुक्त सदस्य चर स्मृति लेता है?

नहीं (यदि यह "वास्तव में" अप्रयुक्त है)।


अब दो सवाल आते हैं:

  1. अवलोकन योग्य व्यवहार कब सदस्य अस्तित्व पर निर्भर नहीं करेगा?
  2. क्या वास्तविक जीवन के कार्यक्रमों में इस तरह की परिस्थितियाँ होती हैं?

एक उदाहरण से शुरू करते हैं।

उदाहरण

#include <iostream>

struct Foo1
{ int var1 = 5;           Foo1() { std::cout << var1; } };

struct Foo2
{ int var1 = 5; int var2; Foo2() { std::cout << var1; } };

void f1() { (void) Foo1{}; }
void f2() { (void) Foo2{}; }

यदि हम gcc को इस अनुवाद इकाई को संकलित करने के लिए कहते हैं , तो यह आउटपुट करता है:

f1():
        mov     esi, 5
        mov     edi, OFFSET FLAT:_ZSt4cout
        jmp     std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
f2():
        jmp     f1()

f2के रूप में ही है f1, और कोई स्मृति कभी भी एक वास्तविक धारण करने के लिए उपयोग नहीं की जाती है Foo2::var2। ( क्लैंग कुछ ऐसा ही करता है )।

विचार-विमर्श

कुछ लोग कह सकते हैं कि यह दो कारणों से अलग है:

  1. यह बहुत ही मामूली उदाहरण है,
  2. संरचना पूरी तरह से अनुकूलित है, इसकी गिनती नहीं है।

ठीक है, एक अच्छा कार्यक्रम जटिल चीजों की एक साधारण जूठन के बजाय सरल चीजों का एक स्मार्ट और जटिल संयोजन है। वास्तविक जीवन में, आप सरल संरचनाओं का उपयोग करते हुए सरल कार्यों के टन लिखते हैं जो संकलक से दूर होता है। उदाहरण के लिए:

bool insert(std::set<int>& set, int value)
{
    return set.insert(value).second;
}

यह डेटा-सदस्य (यहां, std::pair<std::set<int>::iterator, bool>::first) अप्रयुक्त होने का एक वास्तविक उदाहरण है । अंदाज़ा लगाओ? इसे दूर अनुकूलित किया जाता है ( यदि डमी सेट आपको रोता है तो डमी सेट के साथ सरल उदाहरण )।

अब मैक्स लैंगहोफ के उत्कृष्ट उत्तर को पढ़ने के लिए सही समय होगा (कृपया इसे मेरे लिए देखें)। यह बताता है कि आखिरकार, संरचना की अवधारणा असेंबली स्तर पर संकलक आउटपुट से कोई मतलब नहीं है।

"लेकिन, अगर मैं एक्स करता हूं, तो तथ्य यह है कि अप्रयुक्त सदस्य को अनुकूलित किया जाता है एक समस्या है!"

इस उत्तर पर गलत टिप्पणी करने के कई कारण हैं क्योंकि कुछ ऑपरेशन (जैसे assert(sizeof(Foo2) == 2*sizeof(int))) कुछ तोड़ देंगे।

यदि X प्रोग्राम 2 के अवलोकन योग्य व्यवहार का हिस्सा है , तो संकलक को अनुकूलित चीजों को दूर करने की अनुमति नहीं है। एक "अप्रयुक्त" डेटा-सदस्य वाली ऑब्जेक्ट पर बहुत सारे ऑपरेशन होते हैं जो कार्यक्रम पर एक नमूदार प्रभाव डालते हैं। यदि ऐसा कोई ऑपरेशन किया जाता है या यदि कंपाइलर साबित नहीं होता है तो कोई भी प्रदर्शन नहीं किया जाता है, लेकिन "अप्रयुक्त" डेटा-सदस्य प्रोग्राम के अवलोकन योग्य व्यवहार का हिस्सा है और इसे अनुकूलित नहीं किया जा सकता है

वे क्रियाएं जो देखने योग्य व्यवहार को प्रभावित करती हैं, उनमें शामिल हैं, लेकिन इन तक सीमित नहीं हैं:

  • एक प्रकार की वस्तु का आकार लेना ( sizeof(Foo)),
  • "अप्रयुक्त" एक के बाद घोषित एक डेटा सदस्य का पता,
  • किसी फ़ंक्शन के साथ ऑब्जेक्ट की प्रतिलिपि बनाना memcpy,
  • वस्तु के प्रतिनिधित्व में हेरफेर (जैसे memcmp),
  • वाष्पशील के रूप में किसी वस्तु को योग्य बनाना ,
  • आदि

1)

[intro.abstract]/1

इस दस्तावेज़ में शब्दार्थ विवरण एक मानकीकृत nondeterministic सार मशीन को परिभाषित करते हैं। यह दस्तावेज़ अनुरूप कार्यान्वयन की संरचना पर कोई आवश्यकता नहीं रखता है। विशेष रूप से, उन्हें अमूर्त मशीन की संरचना की नकल या अनुकरण करने की आवश्यकता नहीं है। बल्कि, अनुरूप कार्यान्वयन के लिए आवश्यक है (केवल) अमूर्त मशीन के अवलोकन योग्य व्यवहार के रूप में नीचे समझाया गया है।

2) एक जोर से गुजर या असफल की तरह है।


उत्तर में सुधार का सुझाव देने वाली टिप्पणियाँ चैट में संग्रहीत की गई हैं
कोड़ी ग्रे

1
यहां तक कि assert(sizeof(…)…)वास्तव में विवश नहीं करता संकलक यह प्रदान करने के लिए है एक sizeofहै कि जैसी चीजों का उपयोग कर कोड की अनुमति देता है memcpyकाम करने के लिए, लेकिन इसका मतलब यह नहीं है कि किसी भी तरह संकलक है कि कई बाइट का उपयोग करने की आवश्यकता है जब तक कि वे इस तरह के एक से अवगत कराया जा सकता है memcpyकि यह कर सकते हैं 'टी पुनर्लेखन सही मान वैसे भी निर्माण करने के लिए।
डेविस हेरिंग

@ दाविस बिल्कुल।
YSC

63

यह महसूस करना महत्वपूर्ण है कि संकलक का उत्पादन करने वाले कोड को आपके डेटा संरचनाओं का कोई वास्तविक ज्ञान नहीं है (क्योंकि विधानसभा स्तर पर ऐसा कुछ मौजूद नहीं है), और न ही अनुकूलक। कंपाइलर प्रत्येक फ़ंक्शन के लिए केवल कोड का निर्माण करता है , न कि डेटा संरचनाओं का

ठीक है, यह भी निरंतर डेटा अनुभाग और ऐसे लिखता है।

उसके आधार पर, हम पहले ही कह सकते हैं कि ऑप्टिमाइज़र सदस्यों को "हटाएगा" या "समाप्त" नहीं करेगा, क्योंकि यह डेटा संरचनाओं को आउटपुट नहीं करता है। यह कोड आउटपुट करता है , जो सदस्यों का उपयोग नहीं कर सकता है या नहीं कर सकता है , और इसके लक्ष्यों के बीच सदस्यों के व्यर्थ उपयोग (यानी लिखते / पढ़ता है) को समाप्त करके मेमोरी या साइकिल को बचा रहा है ।


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

जैसा कि आप बाहरी दुनिया के साथ एक फंक्शन की बातचीत को कंपाइलर के लिए अधिक जटिल / अस्पष्ट बनाते हैं (अधिक जटिल डेटा संरचनाओं को लेते / वापस करते हैं, उदाहरण के लिए std::vector<Foo>, एक अलग संकलन इकाई में फ़ंक्शन की परिभाषा छिपाते हैं, inlid / dislcentivize inlid etc.) , यह अधिक से अधिक संभावना है कि संकलक साबित नहीं कर सकता है कि अप्रयुक्त सदस्य का कोई प्रभाव नहीं है।

यहां कोई कठिन नियम नहीं हैं क्योंकि यह सब कंपाइलर द्वारा किए गए अनुकूलन पर निर्भर करता है, लेकिन जब तक आप तुच्छ चीजें करते हैं (जैसे कि YSC के उत्तर में दिखाया गया है) यह बहुत संभावना है कि कोई ओवरहेड मौजूद नहीं होगा, जबकि जटिल चीजें करना (जैसे वापस लौटना) एक std::vector<Foo>समारोह से (इनलाइनिंग के लिए बहुत बड़ा) शायद ओवरहेड को उकसाएगा।


बिंदु को समझने के लिए , इस उदाहरण पर विचार करें :

struct Foo {
    int var1 = 3;
    int var2 = 4;
    int var3 = 5;
};

int test()
{
    Foo foo;
    std::array<char, sizeof(Foo)> arr;
    std::memcpy(&arr, &foo, sizeof(Foo));
    return arr[0] + arr[4];
}

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

test(): # @test()
  mov eax, 7
  ret

इतना ही Fooनहीं किसी भी स्मृति पर कब्जा नहीं करने वाले सदस्य Fooभी अस्तित्व में नहीं आए! यदि अन्य उपयोग हैं जो अनुकूलित नहीं किए जा सकते हैं तो उदाहरण के लिए sizeof(Foo)यह महत्वपूर्ण हो सकता है - लेकिन केवल उस खंड के लिए! यदि सभी उपयोगों को इस तरह से अनुकूलित किया जा सकता है, तो उदा का अस्तित्व var3उत्पन्न कोड को प्रभावित नहीं करता है। लेकिन अगर यह कहीं और उपयोग किया जाता है, test()तो भी अनुकूलित रहेगा!

संक्षेप में: प्रत्येक उपयोग Fooस्वतंत्र रूप से अनुकूलित है। कुछ एक अनावश्यक सदस्य के कारण अधिक मेमोरी का उपयोग कर सकते हैं, कुछ नहीं कर सकते हैं। अधिक जानकारी के लिए अपने संकलक मैनुअल से परामर्श करें।


6
माइक ड्रॉप "अधिक जानकारी के लिए अपने कंपाइलर मैनुअल से परामर्श करें।" : D
YSC

22

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

मुझे नहीं लगता कि कोई भी वर्तमान संकलक ऐसे अनुकूलन करता है जब तक कि संरचना वास्तव में उपयोग नहीं की जा रही हो। कुछ संकलक कम से कम अप्रयुक्त निजी चर के बारे में चेतावनी दे सकते हैं लेकिन आमतौर पर सार्वजनिक लोगों के लिए नहीं।


1
और फिर भी यह करता है: Godbolt.org/z/UJKguS + कोई संकलित अप्रयुक्त डेटा सदस्य के लिए चेतावनी नहीं देगा।
YSC

@YSC क्लैंग ++ अप्रयुक्त डेटा सदस्यों और चर के बारे में चेतावनी देता है।
मैक्सिम Egorushkin

3
@ मुझे लगता है कि यह थोड़ी अलग स्थिति है, इसकी संरचना पूरी तरह से अनुकूलित है और सीधे 5 प्रिंट करता है
एलन बर्टल्स

4
@AlanBirtles मैं नहीं देखता कि यह कैसे अलग है। संकलक ने उस वस्तु से सब कुछ अनुकूलित किया जिसका कार्यक्रम के अवलोकन योग्य व्यवहार पर कोई प्रभाव नहीं है। तो आपका पहला वाक्य "कंपाइलर आव्यू को एक अप्रयुक्त सदस्य चर का अनुकूलन करने की संभावना नहीं है" गलत है।
YSC

2
@ YSC वास्तविक कोड में जहां संरचना वास्तव में इसके साइड इफेक्ट्स के लिए निर्मित होने के बजाय इसका उपयोग किया जा रहा है, संभवतः इसकी संभावना अधिक नहीं है इसे दूर अनुकूलित किया जाएगा
एलन बर्टल्स

7

सामान्य तौर पर, आपको यह मान लेना होगा कि आपने जो मांगा है, वह आपको मिल जाएगा, उदाहरण के लिए, "अप्रयुक्त" सदस्य चर हैं।

चूंकि आपके उदाहरण में दोनों सदस्य हैं public, इसलिए कंपाइलर को पता नहीं चल सकता है कि क्या कुछ कोड (विशेष रूप से अन्य अनुवाद इकाइयों = अन्य * .cpp फाइलें, जो अलग-अलग संकलित किए गए हैं और फिर लिंक किए गए) "अप्रयुक्त" सदस्य तक पहुंच जाएंगे।

YSC का उत्तर बहुत सरल उदाहरण देता है, जहां वर्ग प्रकार का उपयोग केवल स्वचालित भंडारण अवधि के चर के रूप में किया जाता है और जहां उस चर का कोई संकेतक नहीं लिया जाता है। वहां, कंपाइलर सभी कोड को इनलाइन कर सकता है और फिर सभी डेड कोड को खत्म कर सकता है।

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

और जब तक आप भाषा की सीमाओं के भीतर हैं, आप यह नहीं देख सकते हैं कि कोई भी उन्मूलन होता है। बुलाएंगे तो sizeof(Foo)मिल जाएगा 2*sizeof(int)। यदि आप एक सरणी बनाते हैं Foo, तो दो लगातार वस्तुओं की शुरुआत के बीच की दूरीFoo हमेशा sizeof(Foo)बाइट्स होती है।

आपका प्रकार एक मानक लेआउट प्रकार है , जिसका अर्थ है कि आप संकलित समय-गणना कंप्यूटर्स (cf. offsetofमैक्रो) के आधार पर सदस्यों तक भी पहुँच सकते हैं । इसके अलावा, आप charउपयोग की एक सरणी पर कॉपी करके ऑब्जेक्ट के बाइट-बाय-बाइट प्रतिनिधित्व का निरीक्षण कर सकते हैं std::memcpy। इन सभी मामलों में, दूसरा सदस्य होने के लिए मनाया जा सकता है।


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
कोड़ी ग्रे

2
+1: केवल आक्रामक पूरे-प्रोग्राम ऑप्टिमाइज़ेशन संभवतः उन मामलों के लिए डेटा लेआउट (संकलन-समय आकार और ऑफ़सेट सहित) समायोजित कर सकते हैं, जहां एक स्थानीय संरचना ऑब्जेक्ट पूरी तरह से अनुकूलित नहीं है, gcc -fwhole-program -O3 *.cसिद्धांत रूप में यह कर सकता है, लेकिन व्यवहार में शायद नहीं होगा। (उदाहरण के मामले में कार्यक्रम sizeof()इस लक्ष्य पर सटीक मूल्य के बारे में कुछ धारणाएं बनाता है , और क्योंकि यह वास्तव में जटिल अनुकूलन है जो प्रोग्रामर को हाथ से करना चाहिए यदि वे इसे चाहते हैं।)
पीटर कॉर्डेस

6

इस सवाल के अन्य उत्तरों द्वारा प्रदान किए गए उदाहरण, जो var2एक ही अनुकूलन तकनीक पर आधारित हैं: निरंतर प्रचार, और बाद में पूरी संरचना के बाद (न कि केवल चीराvar2 । यह सरल मामला है, और अनुकूलन करने वाले संकलन इसे लागू करते हैं।

अप्रबंधित C / C ++ कोड के लिए उत्तर है कि संकलक सामान्य रूप से नहीं होगा var2। जहां तक ​​मुझे पता है कि डिबगिंग जानकारी में इस तरह के सी / सी ++ संरचना परिवर्तन के लिए कोई समर्थन नहीं है, और यदि यह संरचना डिबगर में एक चर के रूप में सुलभ है, तो var2इसे समाप्त नहीं किया जा सकता है। जहां तक ​​मुझे पता है कि कोई वर्तमान C / C ++ कंपाइलर के अनुसार नहीं हो सकता है var2, इसलिए यदि संरचना को पारित किया गया है या एक गैर-इनबिल्ट फ़ंक्शन से लौटा है, तो var2एलर्ड नहीं किया जा सकता है।

JIT कंपाइलर के साथ C # / Java जैसी प्रबंधित भाषाओं के लिए कंपाइलर सुरक्षित रूप से सक्षम हो सकता है var2क्योंकि यह ठीक से ट्रैक कर सकता है यदि इसका उपयोग किया जा रहा है और क्या यह अप्रबंधित कोड से बच जाता है। प्रबंधित भाषाओं में संरचना का भौतिक आकार प्रोग्रामर को बताए गए इसके आकार से भिन्न हो सकता है।

वर्ष 2019 C / C ++ कंपाइलर var2संरचना से अलग नहीं हो सकते , जब तक कि पूरे स्ट्रक्चर वेरिएबल को एलेड न कर दिया जाए। var2संरचना से उत्तीर्ण होने के दिलचस्प मामलों के लिए, उत्तर है: नहीं।

कुछ भविष्य के C / C ++ कंपाइलर var2संरचना से अलग हो सकेंगे , और कंपाइलरों के चारों ओर बने इकोसिस्टम को कंपाइलरों द्वारा बनाई गई एलिसन सूचना को प्रोसेस करने के लिए अनुकूल बनाने की आवश्यकता होगी।


1
डिबग जानकारी के बारे में आपका पैराग्राफ "हम इसे दूर अनुकूलित नहीं कर सकते हैं यदि यह डिबगिंग को कठिन बना देगा", जो कि केवल स्पष्ट गलत है। या मैं गलत बोल रहा हूं। क्या आप स्पष्ट कर सकते हैं?
मैक्स लैंगहॉफ

यदि कंपाइलर संरचना के बारे में डिबग जानकारी का उत्सर्जन करता है तो यह var2 को समाप्त नहीं कर सकता है। विकल्प हैं: (1) संरचना के भौतिक प्रतिनिधित्व के अनुरूप नहीं होने पर डिबग जानकारी का उत्सर्जन न करें, (2) डिबग सूचना में समर्थन सदस्य सदस्य के
तर्क

शायद अधिक सामान्य है, स्केगर रिप्लेसमेंट ऑफ एग्रीगेट्स (और फिर मृतक भंडार इत्यादि का उल्लेख )।
डेविस हेरिंग

4

यह आपके कंपाइलर और इसके अनुकूलन स्तर पर निर्भर है।

जीसीसी में, यदि आप निर्दिष्ट करते हैं -O, तो यह निम्नलिखित अनुकूलन झंडे को चालू करेगा :

-fauto-inc-dec 
-fbranch-count-reg 
-fcombine-stack-adjustments 
-fcompare-elim 
-fcprop-registers 
-fdce
-fdefer-pop
...

-fdceमृत कोड उन्मूलन के लिए खड़ा है ।

आप __attribute__((used))स्थैतिक भंडारण के साथ अप्रयुक्त चर को नष्ट करने से रोकने के लिए उपयोग कर सकते हैं :

स्थैतिक भंडारण के साथ एक चर से जुड़ी यह विशेषता, इसका मतलब है कि चर को उत्सर्जित किया जाना चाहिए, भले ही ऐसा प्रतीत हो कि चर संदर्भित नहीं है।

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


यह स्थिर डेटा सदस्यों के लिए है, अप्रयुक्त-प्रति-सदस्य सदस्य नहीं (जो तब तक अनुकूलित नहीं होते जब तक कि पूरी वस्तु नहीं हो जाती)। लेकिन हां, मुझे लगता है कि गिनती होती है। BTW, अप्रयुक्त स्थिर वैरिएबल्स को समाप्त करना मृत कोड उन्मूलन नहीं है, जब तक कि GCC शब्द झुकता नहीं है।
पीटर कॉर्ड्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.