C ++ में "जहर ए फंक्शन" का क्या मतलब है?


96

CppCon में स्कॉट शूर की बातचीत "इंट्रोड्यूसिंग constexpr" के बहुत अंत में , वह पूछता है "क्या एक समारोह में जहर है?" फिर वह बताते हैं कि यह किया जा सकता है (गैर-मानक तरीके से):

  1. throwकिसी constexprफंक्शन में लगाना
  2. एक अनसुलझी घोषणा extern const char*
  3. में अनसुलझे externको संदर्भितthrow

मुझे लगता है कि मैं यहाँ अपनी गहराई से थोड़ा बाहर हूँ, लेकिन मैं उत्सुक हूँ:

  • "जहर एक समारोह" का क्या मतलब है?
  • वह जिस तकनीक को रेखांकित करता है उसका महत्व / उपयोगिता क्या है?

1
उस शब्द के बारे में कभी नहीं सुना, संक्षिप्त उदाहरण के साथ स्पष्ट करें!
πάν 20α ῥεῖ

6
@ .ν .αῥεῖ, मैंने अभी स्पष्ट किया है। यह शब्द 'व्यापक रूप से छोटे हलकों में जाना जाता है'
सर्गेइया नोवा

4
वह यह सुनिश्चित करने के बारे में बात कर रहा है कि constexprसंकलन के समय फ़ंक्शन के प्रत्येक कॉल का मूल्यांकन किया जाता है।
TC

@ टीटी राइट - उन्होंने उल्लेख किया कि एक constexprफ़ंक्शन का उपयोग संकलन समय पर या रन टाइम में किया जा सकता है। तो यह इसे मजबूर करने का एक तरीका है ताकि आप इसे रन टाइम पर उपयोग न कर सकें? वह कब उपयोगी है?
सुडू

3
विशेष रूप से सी ++ 11 में, एक constexprसमारोह अक्सर बाधाओं के कारण सबसे कुशल कार्यान्वयन नहीं होता है, इसलिए कोई यह नहीं चाहता है कि यह रन टाइम पर मूल्यांकन किया जाए; या, शायद यह त्रुटि का मामला है (जैसा कि उनके उदाहरण में)।
टीसी

जवाबों:


106

सामान्य तौर पर यह एक फ़ंक्शन को अनुपयोगी बनाने के लिए संदर्भित करता है, उदाहरण के लिए यदि आप किसी प्रोग्राम में डायनेमिक आवंटन के उपयोग पर प्रतिबंध लगाना चाहते हैं, तो आप mallocफ़ंक्शन को "जहर" कर सकते हैं, इसलिए इसका उपयोग नहीं किया जा सकता है।

वीडियो में वह इसे और अधिक विशिष्ट तरीके से उपयोग कर रहा है, जो स्पष्ट है यदि आप उस स्लाइड को पढ़ते हैं जो प्रदर्शित होने पर वह फ़ंक्शन को जहर देने की बात करता है, जो कहता है "केवल संकलन-समय को मजबूर करने का एक तरीका?"

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

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

क्योंकि अपरिभाषित प्रतीक फ़ंक्शन के संकलन-समय के इनवोकेशन में "odr-used" नहीं है, व्यवहार में संकलक प्रतीक का संदर्भ नहीं बनाएगा, इसलिए यह ठीक है कि यह अपरिभाषित है।

क्या यह उपयोगी है? वह दिखा रहा है कि यह कैसे करना है, जरूरी नहीं कि यह एक अच्छा विचार है या व्यापक रूप से उपयोगी है। यदि आपको किसी कारण से ऐसा करने की आवश्यकता है तो उसकी तकनीक आपकी समस्या का समाधान कर सकती है। यदि आपको इसकी आवश्यकता नहीं है, तो आपको इसके बारे में चिंता करने की आवश्यकता नहीं है।

एक कारण यह उपयोगी हो सकता है जब कुछ ऑपरेशन का संकलन-समय संस्करण उतना कुशल नहीं है जितना यह हो सकता है। एक कॉन्स्ट्रेक्स फ़ंक्शन (विशेष रूप से C ++ 11 में, C ++ 14 में कुछ प्रतिबंध हटा दिए गए थे) पर इस तरह के अभिव्यक्ति की अनुमति है। तो आपके पास गणना करने के लिए एक फ़ंक्शन के दो संस्करण हो सकते हैं, एक जो कि इष्टतम है, लेकिन उन अभिव्यक्तियों का उपयोग करता है जिन्हें एक कॉन्स्ट्रेक्स फ़ंक्शन में अनुमति नहीं है, और एक जो एक वैध कॉन्स्ट्रेक्स फ़ंक्शन है, लेकिन रन-टू में कॉल किए जाने पर खराब प्रदर्शन करेगा समय। आप यह सुनिश्चित करने के लिए उप-इष्टतम एक को जहर कर सकते हैं कि इसे रन-टाइम कॉल के लिए कभी उपयोग नहीं किया जाता है, रन-टाइम कॉल के लिए अधिक कुशल (गैर-कॉन्स्ट्रेक्स) संस्करण का उपयोग किया जाता है।

NB संकलन-समय पर उपयोग किए जाने वाले एक कॉन्स्ट्रेक्स फ़ंक्शन का प्रदर्शन वास्तव में महत्वपूर्ण नहीं है, क्योंकि इसके पास कोई रन-टाइम ओवरहेड नहीं है। यह कंपाइलर को अतिरिक्त काम करके आपके संकलन को धीमा कर सकता है, लेकिन इसमें कोई रन-टाइम प्रदर्शन लागत नहीं होगी।


1
मैंने स्लाइड का पाठ पढ़ा था, लेकिन मैं उस शब्द का कनेक्शन नहीं देख रहा था जिसका वह उपयोग कर रहा था। अब यह स्पष्ट है कि आपने इसे स्पष्ट कर दिया है, लेकिन मैंने इसे उस समय नहीं देखा था। इस उत्कृष्ट उत्तर के लिए बहुत बहुत धन्यवाद - मुझे सिर्फ इस वेबसाइट से प्यार है।
सूडो

@PravasiMeet, अपना स्वयं का प्रश्न पूछें, किसी और की टिप्पणी के बारे में किसी और चीज़ के बारे में टिप्पणी न करें। एक सरल समाधान यह होगा कि इसे हर अनुवाद इकाई में हटा दिया जाए, या इसे अपनी परिभाषा से बदल दिया जाए जो एक अपरिभाषित प्रतीक का संदर्भ देता है।
जोनाथन वैखली

17

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

जीसीसी में पारंपरिक रूप से इसके लिए एक प्रज्ञा थी #pragma GCC poison:।


1
हां, लेकिन उस बात में इस्तेमाल किए गए अर्थों में काफी नहीं।
TC

@TC, ठीक है, मुझे शायद जवाब देने से पहले इसे देखना चाहिए :)
सर्गेइया नोवा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.