2012-07-18 9 views
12

मैं कुछ सी ++ स्थिर विश्लेषण नियमों को लागू करने रहा हूँ, और उनमें से एक समारोह के लिए एक संदर्भ पैरामीटर के लिए एक संदर्भ या सूचक लौटने, यानी निम्न से एक समारोह पर प्रतिबंध लगाता है सभी असंगत हैं:क्या यह सी ++ स्थिर विश्लेषण नियम समझ में आता है?

int *f(int& x) { return &x; } // #1 
const int *g(const int& x) { return &x; } // #2 
int& h(int& x) { return x; } // #3 
const int& m(const int& x) { return x; } // #4 

इसके लिए दिया गया औचित्य यह है कि "यह कार्यान्वयन-परिभाषित व्यवहार है कि संदर्भ पैरामीटर एक अस्थायी वस्तु है या पैरामीटर का संदर्भ है।"

मैं इस से परेशान हूं, हालांकि, सी ++ में स्ट्रीम ऑपरेटर इस तरह से लिखे गए हैं, उदा।

std::ostream& operator<<(std::ostream& os, const X& x) { 
    //... 
    return os; 
} 

मुझे लगता है कि मैं बहुत विश्वास है कि सी ++ में धारा ऑपरेटरों सामान्य प्रदर्शनी कार्यान्वयन से परिभाषित व्यवहार में नहीं है कर रहा हूँ, तो क्या हो रहा है?

मेरी समझ के अनुसार वर्तमान में, मैं उम्मीद करता हूं कि # 1 और # 3 अच्छी तरह से परिभाषित किए जाएंगे, इस आधार पर कि अस्थायी गैर-कॉन्स्ट संदर्भों के लिए बाध्य नहीं हो सकते हैं, इसलिए int& x वास्तविक वस्तु को संदर्भित करता है कार्यकाल के दायरे से बाहर जीवनकाल है, इसलिए उस वस्तु के सूचक या संदर्भ को वापस करना ठीक है। मैं उम्मीद करता हूं कि # 2 डोडी हो, क्योंकि अस्थायी const int& x तक सीमित हो सकता है, जिस स्थिति में अपना पता लेने की कोशिश की जा रही है, यह एक खराब योजना प्रतीत होगी। मुझे यकीन नहीं है कि # 4 - मेरा आंत महसूस यह है कि यह भी संभावित रूप से डोडी है, लेकिन मुझे यकीन नहीं है। विशेष रूप से, मैं क्या निम्नलिखित मामले में क्या होगा पर स्पष्ट नहीं कर रहा हूँ:

const int& m(const int& x) { return x; } 
//... 
const int& r = m(23); 
+0

आप MSVC++ का उपयोग कर रहे हैं? – Nawaz

+0

@ नवाज: मैं बड़े कोड-बेस पर प्रश्न लिखने के लिए .QL का उपयोग कर रहा हूं :) मुझे नहीं लगता कि यह किस कंपाइलर से कोई फर्क नहीं पड़ता, मैं आदर्श रूप से एक मंच-स्वतंत्र उत्तर की तलाश में हूं। –

+2

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

उत्तर

8

आप कहते हैं के रूप में, # 1 और # 3 ठीक हैं (हालांकि # 1 यकीनन बुरा शैली है)।

# 4 इसी कारण से # 2 है; यह अपने जीवनकाल के अस्थायी अस्थायी संदर्भ को बढ़ावा देने की अनुमति देता है।

आइए जांच:

#include <iostream> 

struct C { 
    C() { std::cout << "C()\n"; } 
    ~C() { std::cout << "~C()\n"; } 
    C(const C &) { std::cout << "C(const C &)\n"; } 
}; 

const C &foo(const C &c) { return c; } 

int main() { 
    const C &c = foo(C()); 
    std::cout << "c in scope\n"; 
} 

यह आउटपुट:

C() 
~C() 
c in scope 
+0

धन्यवाद - मुझे यकीन नहीं था कि अस्थायी जीवनकाल इस तरह की चीज करके लंबे समय तक किया जाएगा या नहीं। ऐसा लगता है कि उत्तर एक फर्म 'नहीं' है, टा। –

+0

और स्ट्रीम ऑपरेटर के बारे में क्या? – Arne

+3

@Arne: वे एक गैर-कॉन्स्ट संदर्भ लेते हैं और वापस करते हैं, इसलिए वे ठीक हैं। –

1

सी ++ 11, # 2 और # 4 बनाया जा सकता है सुरक्षित अगर वहाँ भी कर रहे हैं rvalue संदर्भ भार के हैं। इस प्रकार:

const int *get(const int &x) { return &x; } 
const int *get(const int &&x) { return nullptr; } 

void test() { 
    const int x = 0; 
    const int *p1 = get(x); // OK; p1 is &x. 
    const int *p2 = get(x+42); // OK; p2 is nullptr. 
} 

तो हालांकि वे डोडी हैं, लेकिन प्रोग्रामर जानता है कि वे क्या कर रहे हैं, उनके पास सुरक्षित उपयोग हैं। यह मना करने के लिए draconian होगा।

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

+0

धन्यवाद, अच्छे अंक, खासकर भविष्य के लिए। इसका संदर्भ यह है कि मैं अपने वाणिज्यिक उपकरण के लिए एक काफी draconian नियम सेट लागू कर रहा हूं - वे मानक द्वारा पिन किए गए हैं, इसलिए मुझे नियमों के पत्र से बहुत दूर विचलन करने के बारे में सावधान रहना होगा। उस ने कहा, लक्ष्य जहां भी संभव हो झूठी सकारात्मक को कम करना है। हम अभी तक सी ++ 11 का समर्थन नहीं करते हैं, लेकिन जब हम करते हैं तो मैं निश्चित रूप से खाते में रावल्यू संदर्भ अधिभार लेने के लिए नियम को संशोधित करने के इच्छुक हूं। –

+0

उन मामलों में से एक जहां एक रावल्यू पैरामीटर के संदर्भ को वापस करना "सुरक्षित" है 'std :: move' और 'std :: forward' के साथ है, जो दोनों रावल्यू तर्क ले सकते हैं। IOW, यदि आप इस तरह के फ़ंक्शन के परिणाम को सीधे किसी अन्य अभिव्यक्ति के पास पारित करने की योजना बना रहे हैं, जो भी हो (अन्य फ़ंक्शन की तरह)। – Xeo