2011-07-08 14 views
13

क्या सी ++ में यह घोषणा करने का कोई तरीका है कि किसी फ़ंक्शन का दुष्प्रभाव नहीं है? पर विचार करें:सी ++: कोई साइड इफेक्ट्स के साथ फ़ंक्शन अनुकूलित करना

LOG("message").SetCategory(GetCategory()); 

अब रिलीज में लॉग मैक्रो बनाता है एक NullLogEntry उद्देश्य यह है कि SetCategory है() एक खाली समारोह के रूप में परिभाषित बनाता है कि लगता है। तो मूल रूप से पूरी अभिव्यक्ति को अनुकूलित किया जा सकता है (और चाहिए) को दूर किया जा सकता है - सिद्धांत रूप में, GetCategory() कॉल के कुछ दुष्प्रभाव हो सकते हैं, इसलिए मुझे लगता है कि संकलक को इसे फेंकने की अनुमति नहीं है।

एक और उदाहरण एक फ़ंक्शन टेम्पलेट विशेषज्ञता हो सकता है जो इसके कुछ तर्कों को अनदेखा करता है, फिर भी संकलक को संभव साइड इफेक्ट्स के कारण कॉल साइट पर ऐसे तर्कों के मूल्यांकन को सहेजने की अनुमति नहीं है।

क्या मैं सही हूँ? या फिर संकलक इस तरह के कॉल को अनुकूलित कर सकते हैं? यदि नहीं, तो क्या संकलक को संकेत देने का कोई तरीका है कि इस फ़ंक्शन का कोई साइड इफेक्ट नहीं है, इसलिए यदि वापसी मान को अनदेखा किया जाता है तो पूरी कॉल छोड़ी जा सकती है?

+0

जब तक कि फ़ंक्शन इनलाइन होने के लिए पर्याप्त छोटा हो, तब तक बाधाएं बहुत अच्छी होती हैं कि सभी कोड को अनुकूलित किया जाता है।जाहिर है यह एक कार्यान्वयन विस्तार है जिसे आपको अपने लिए सत्यापित करना होगा। –

+0

मूल रूप से अनुकूलक के दौरान किसी भी * अर्थपूर्ण * परिवर्तन करने की अनुमति नहीं है। फ़ंक्शन कॉल को निकालना एक अर्थपूर्ण परिवर्तन है। चूंकि आप संकलक को स्पष्ट रूप से नहीं बता सकते हैं "इस फ़ंक्शन का कोई साइड इफेक्ट नहीं है", यह अनुकूलित नहीं होगा। –

+0

@Cicada: कुछ सी ++ कंपाइलर्स गुणों को परिभाषित करते हैं (जैसे 'शुद्ध') जो आपको संकलक को बताते हैं कि फ़ंक्शन का कोई साइड इफेक्ट नहीं है, जिससे सिद्धांत में, इसके परिणाम कैश हो सकते हैं/इसकी कॉल अनुकूलित कर सकते हैं। –

उत्तर

16

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

char * str = get_some_string(); 
int __length = strlen(str); 
for (int i = 0; i < __length; ++ i) { 
    str[i] = toupper(str[i]); 
} 

समारोह के रूप में string.h शीर्षक में घोषित किया जाता है:

char * str = get_some_string(); 
for (int i = 0; i < strlen(str); ++i) { 
    str[i] = toupper(str[i]); 
} 

में संकलक द्वारा अनुकूलित किया जा सकता है

extern size_t strlen (__const char *__s) 
    __THROW __attribute_pure__ __nonnull ((1)); 

कहाँ __THROW मामले में एक नहीं फेंक अपवाद है कि यह एक सी ++ संकलक समारोह को पार्स है, और __nonnull((1)) संकलक बताता है कि पहले तर्क रों शून्य नहीं हो सकता है (यानी। अगर तर्क शून्य है और चेतावनी ध्वज का उपयोग किया जाता है तो चेतावनी ट्रिगर करें)।

+1

यह आशाजनक लग रहा है। किसी को भी एमएसवीसी में समान कुछ पता है? (बेशक एक मानक समाधान बेहतर होगा, लेकिन अच्छी तरह से ...) – imre

+0

@ डेविड: क्या आप जानते हैं कि कंपाइलर फ़ंक्शन परिभाषा wrt purity को मारते समय कोई जांच करता है या नहीं? –

+0

@imre: यदि आपके पास एमएसवीसी स्थापित है, तो 'strlen' पर एक नज़र डालने का प्रयास करें, इसमें एक समान विशेषता परिभाषित हो सकती है, यह एक ऐसे फ़ंक्शन का एक अच्छा उदाहरण है जो मानक में * शुद्ध * होना जाता है ताकि यह होगा उस विशेषता का उपयोग करने के लिए कार्यान्वयनकर्ताओं के लिए एक अच्छा उम्मीदवार बनें। –

4

कंपाइलर अपारदर्शी फ़ंक्शन को कॉल को ऑप्टिमाइज़ नहीं कर सकता है। हालांकि, अगर GetCategory इनलाइन है, और इसलिए कॉल साइट पर दिखाई देता है, तो संकलक को पर अनुमति दी जाती है, और अधिकांश मामलों में यह ऑप्टिमाइज़ हो जाएगा यदि यह देखता है कि इसका दुष्प्रभाव नहीं है, लेकिन यह अनिवार्य नहीं है ऐसा करो।

100% निश्चितता के साथ आप जो चाहते हैं उसे प्राप्त करने के लिए आपको पूरे कथन को एक मैक्रो में लपेटने की आवश्यकता है जो आपकी रिलीज कॉन्फ़िगरेशन के लिए खाली कथन का मूल्यांकन करेगी।

+0

मदद करने के लिए जा रहे मैक्रो में एक कथन कैसे लपेट रहा है? जब तक कोड संकलक को उचित रूप से प्राप्त हो जाता है, तब तक मैक्रो मौजूद नहीं होता है। इसे विस्तारित किया गया है। ** संपादित करें ** कभी भी ध्यान न दें। मैक्रो उत्पादन मोड में कुछ भी नहीं फैलता है। –

+0

@ डेविड, मुझे और अधिक स्पष्ट होना चाहिए था। संपादित। –

+1

हाँ, मैं पूरी तरह से एक मैक्रो में लपेटने के विकल्प से अवगत हूं, लेकिन मैं इसे दो कारणों से समाधान के रूप में नापसंद करता हूं: ए) यह थोड़ा बदसूरत है, और बी) किसी भी तरह मुझे लगता है कि अभी भी अगर मैं अभी भी कर सकता हूं केवल इन दो उदाहरणों के साथ आते हैं, यह वास्तव में एक और सामान्य समस्या है, और कार्यों को ध्वजांकित करने की क्षमता के रूप में कोई दुष्प्रभाव नहीं हो सकता है। केवल इनलाइन फ़ंक्शंस को अनुकूलित करना वास्तव में पर्याप्त नहीं है; एक फ़ंक्शन तर्क बहुत ही जटिल गणना (कोई दुष्प्रभाव नहीं) का परिणाम हो सकता है, और यदि इसे अनदेखा किया जाता है, तो भी पूरी कॉल को छोड़ना अच्छा होगा। – imre

3

यह डीबग मोड कोड के साथ एक पता समस्या है।

एकमात्र विश्वसनीय समाधान (फ़ंक्शन कॉल के लिए) मैक्रो के भीतर सभी डिबगिंग कोड को लपेटना है।

उदाहरण के लिए, आप शायद निम्न कोड के बजाय इस्तेमाल कर सकते हैं:

LOG("message", GetCategory()); 

फिर पूर्वप्रक्रमक रिलीज में पूरे बयान का सफाया होता है, और आप इस बारे में किसी भी अब चिंता करने की ज़रूरत नहीं होगी।

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