2014-06-19 11 views
7

का पता लेना this सी ++ एफएक्यू क्या व्यक्त करने का प्रयास करता है?एक स्थिर सदस्य सी ++ एफएक्यू

You can take the address of a static member if (and only if) it has an out-of-class definition :

class AE { 
    // ... 
public: 
    static const int c6 = 7; 
    static const int c7 = 31; 
}; 

const int AE::c7; // definition 

int f() 
{ 
    const int* p1 = &AE::c6; // error: c6 not an lvalue 
    const int* p2 = &AE::c7; // ok 
    // ... 
} 

हालांकि इस compiles !

+1

यदि आप 'कक्षा एई' और 'एफ()' अलग से संकलित करते हैं और फिर ऑब्जेक्ट को लिंक करते हैं तो क्या होता है? – juanchopanza

+1

@juanchopanza यह '-O2' और 'f()' के साथ संकलित है अनिवार्य रूप से एक एनओपी है। हालांकि, यह '-O0' के साथ एक लिंकर त्रुटि देता है, जैसे मूल प्रोग्राम '-O0' के साथ करता है। – Csq

+0

@Csq हां, मैंने देखा और आपका जवाब वोट दिया। वैकल्पिक रूप से, 'std :: cout << p1 << std :: endl; 'एक सेशन में बना देगा। – juanchopanza

उत्तर

5

पूछे जाने वाले प्रश्न में टिप्पणी बहुत भ्रामक है उपयोग करने के लिए शुरू एक लिंकर त्रुटि मिलती है; AE::c6 और AE::c7 दोनों हैं lvalues। अगर वहाँ AE::c7, की कोई परिभाषा है प्रश्न में कोड एक परिभाषा नियम का उल्लंघन करती:

An expression is potentially evaluated unless it is an unevaluated operand or a subexpression thereof. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression and the lvalue-to-rvalue conversion is immediately applied. [...]

[...]

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.

अभ्यास में, लिंकर आम तौर पर एक त्रुटि उत्पन्न होगा अगर संकलक वास्तव में वस्तु का पता की जरूरत है। आपके मामले में, यदि p2 बाद में उपयोग नहीं किया जाता है, तो संकलक को पता की आवश्यकता नहीं होगी, क्योंकि अनुकूलन p1 की परिभाषा को हटा देगा। इससे भी अधिक लगातार इस मामले में जहां यह तब होता है निम्नलिखित तरह बातें कर रहे हैं:

std::vector<int> v; 
v.push_back(AE::c6); 

std::vector<>::push_back के बाद से एक संदर्भ लेता है, कोई तत्काल lvalue करने वाली rvalue रूपांतरण है, और एक परिभाषा आवश्यक है। अभ्यास में, std::vector<>::push_back एक टेम्पलेट फ़ंक्शन (आमतौर पर इनलाइन) है, इसलिए कंपाइलर अपने कार्यान्वयन में देख सकता है, और उस स्थान पर मान को में प्रसारित करता है जहां वास्तव में lvalue-to-rvalue रूपांतरण होता है, और कोड संकलित और काम करेगा। लेकिन यह अभी भी औपचारिक रूप से अपरिभाषित व्यवहार है।

9

आप -O2 का उपयोग संकलित करने के लिए। संकलक const int* p1 = &AE::c6; असाइनमेंट को अनुकूलित कर सकता है (क्योंकि इसका कोई प्रभाव नहीं है) और इसलिए इसे अंतिम कोड में AE::c6 के पते की आवश्यकता नहीं है, यही कारण है कि यह संकलित करता है।

यह अनुकूलन के बिना एक लिंकर त्रुटि देता है।

अगर आपको p1 (जैसे std::cout << p1 << p2 << std::endl;) Link

+0

ठीक है, मैं वही बात यहां भी कहूंगा (जैसा कि मैंने कहा था हटाए गए उत्तर में से एक था), टिप्पणी '// त्रुटि: c6 एफएक्यू में एक लालसा नहीं 'आईएमओ भ्रामक है, जो पहली नज़र में एक वाक्य रचनात्मक त्रुटि प्रतीत होता है। लिंकर त्रुटि स्पष्ट थी, लेकिन अनुकूलन के बाद मुझे आश्चर्यजनक रूप से अज्ञात – P0W

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