नोरटर्न का क्या मतलब है?


189

[dcl.attr.noreturn] निम्नलिखित उदाहरण प्रदान करता है:

[[ noreturn ]] void f() {
    throw "error";
    // OK
}

लेकिन मुझे समझ में नहीं आ रहा है कि क्या बात है [[noreturn]], क्योंकि फ़ंक्शन का वापसी प्रकार पहले से ही है void

तो, noreturnविशेषता का क्या मतलब है ? इसका उपयोग कैसे किया जाना चाहिए?


1
इस तरह के कवक के बारे में इतना महत्वपूर्ण क्या है (जो कि एक कार्यक्रम के निष्पादन में एक बार होने की संभावना है) जो इस तरह के ध्यान का हकदार है? क्या यह आसानी से पता लगाने योग्य स्थिति नहीं है?
user666412

1
@ मस्टरिस्टर ओपी के "रिटर्निंग" और "रिटर्न वैल्यू" की अवधारणाओं को स्वीकार कर रहा है। यह देखते हुए कि कैसे वे लगभग हमेशा मिलकर बने रहते हैं, मुझे लगता है कि भ्रम उचित है।
स्लिप डी। थॉम्पसन

जवाबों:


209

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

इसका उपयोग कंपाइलर द्वारा कुछ अनुकूलन करने और बेहतर चेतावनी उत्पन्न करने के लिए किया जा सकता है। उदाहरण के लिए, अगर fनोटरी विशेषता है, तो संकलक g()आपको लिखते समय मृत कोड होने के बारे में चेतावनी दे सकता है f(); g();। इसी तरह से कंपाइलर आपको कॉल करने के बाद लापता रिटर्न स्टेटमेंट के बारे में आगाह नहीं करेगा f()


5
एक समारोह के बारे में क्या इस तरह के रूप execveकि नहीं होना चाहिए लौटने लेकिन सकता है ? क्या इसमें नोटरी विशेषता होनी चाहिए ?
कालिश

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

6
@ SlippD.Thompson अगर एक नोटरी फ़ंक्शन के लिए कॉल एक कोशिश-ब्लॉक में लपेटी जाती है, तो पकड़ने वाले ब्लॉक के किसी भी कोड को फिर से पहुंच के रूप में गिना जाएगा।
sepp2k

2
@ sepp2k कूल। तो यह असंभव नहीं है, बस असामान्य है। यह उपयोगी है। चीयर्स।
स्लिप डी। थॉम्पसन

7
@ SlippD.Thompson नहीं, लौटना असंभव है। एक अपवाद को फेंकना वापस नहीं आ रहा है, इसलिए यदि हर रास्ता फेंकता है तो यह है noreturn। उस अपवाद को संभालना वैसा नहीं है, जैसा वह लौटा है। tryकॉल के बाद के भीतर कोई भी कोड अभी भी पहुंच से बाहर है, और यदि नहीं voidतो रिटर्न वैल्यू का कोई भी असाइनमेंट या उपयोग नहीं होगा।
जॉन हैना

63

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


29

इसका मतलब है कि फ़ंक्शन पूरा नहीं होगा। नियंत्रण प्रवाह कॉल के बाद कभी भी स्टेटमेंट को हिट नहीं करेगा f():

void g() {
   f();
   // unreachable:
   std::cout << "No! That's impossible" << std::endl;
}

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



4
@TemplateRex: के साथ संकलित करें -Wno-returnऔर आपको एक चेतावनी मिलेगी। संभवत: वह नहीं जिसकी आप उम्मीद कर रहे थे लेकिन यह बताने के लिए शायद पर्याप्त है कि संकलक को इस बात का ज्ञान है कि [[noreturn]]वह इसका क्या लाभ उठा सकता है। (मैं थोड़ा हैरान हूं कि -Wunreachable-codeइसमें किक नहीं हुई ...)
डेविड रोड्रिगेज - dribeas

3
@TemplateRex: क्षमा करें -Wmissing-noreturn, तात्पर्य यह है कि प्रवाह विश्लेषण यह निर्धारित करता है कि उपलब्ध std::coutनहीं है। जनरेट असेंबली को देखने के लिए मेरे पास एक नया पर्याप्त gcc नहीं है, लेकिन कॉल operator<<ड्रॉप होने पर मुझे आश्चर्य नहीं होगा
डेविड रॉड्रिग्ज़ - dribeas

1
यहां एक विधानसभा डंप (-S -o - कोलीरू में झंडे) है, जो वास्तव में "अगम्य" कोड को गिराता है। दिलचस्प रूप से पर्याप्त है, -O1पहले से ही[[noreturn]] संकेत के बिना उस अगम्य कोड को छोड़ने के लिए पर्याप्त है ।
टेम्प्लेक्स

2
@TemplateRex: सभी कोड एक ही अनुवाद इकाई और दृश्यमान में हैं, इसलिए संकलक [[noreturn]]कोड से अनुमान लगा सकता है । यदि इस अनुवाद इकाई के पास केवल उस फ़ंक्शन की घोषणा थी जो कहीं और परिभाषित की गई थी, तो संकलक उस कोड को नहीं छोड़ पाएगा, क्योंकि यह नहीं जानता है कि फ़ंक्शन वापस नहीं आता है। यह वह जगह है जहाँ गुण संकलक की मदद करनी चाहिए।
डेविड रॉड्रिग्ज - dribeas

17

पिछले उत्तरों ने स्पष्ट रूप से समझाया कि क्या है, नॉटटर्न क्या है, लेकिन ऐसा क्यों नहीं है। मुझे नहीं लगता कि "अनुकूलन" टिप्पणी मुख्य उद्देश्य है: ऐसे कार्य जो वापस नहीं आते हैं दुर्लभ हैं और आमतौर पर अनुकूलित करने की आवश्यकता नहीं है। बल्कि मुझे लगता है कि नोटरी का मुख्य जेल डी-लेटर झूठे-सकारात्मक चेतावनियों से बचने के लिए है। उदाहरण के लिए, इस कोड पर विचार करें:

int f(bool b){
    if (b) {
        return 7;
    } else {
        abort();
    }
 }

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


सूचीबद्ध अन्य सभी उदाहरण शून्य कार्यों का उपयोग करते हैं - यह कैसे काम करता है जब आपके पास [[कोई वापसी नहीं]] निर्देश और एक गैर-शून्य रिटर्न प्रकार है? क्या [[कोई वापसी नहीं]] निर्देश केवल तभी चलन में आता है जब कंपाइलर वापस न आने और चेतावनी को नजरअंदाज करने की संभावना के बारे में चेतावनी देने के लिए तैयार हो जाता है? उदाहरण के लिए, संकलक जाता है: "ठीक है, यहां एक गैर-शून्य फ़ंक्शन है।" * संकलन जारी है * "ओह बकवास, यह कोड वापस नहीं आ सकता है? क्या मुझे उपयोगकर्ता को चेतावनी देनी चाहिए? *" कोई बात नहीं, मैं नो-रिटर्न निर्देश देखता हूं। कैरी ऑन "
रैले एल।

2
मेरे उदाहरण में नोटरी फ़ंक्शन f () नहीं है, यह abort () है। यह एक गैर-शून्य फ़ंक्शन को चिह्नित नहीं करता है। एक फ़ंक्शन जो कभी-कभी एक मान लौटाता है और कभी-कभी रिटर्न (एक अच्छा उदाहरण निष्पादित होता है) () नॉटआउट को चिह्नित नहीं किया जा सकता है।
नदव हर'एल

1
निहित-पतन एक और ऐसा उदाहरण है: stackoverflow.com/questions/45129741/…
Ciro Santilli 病 is is 六四 事件

11

सैद्धांतिक रूप से बोलना, voidवह है जिसे अन्य भाषाओं में कहा जाता है unitया top। इसका तार्किक समकक्ष सत्य है । किसी भी मूल्य को वैध रूप से डाला जा सकता है void(हर प्रकार का एक उपप्रकार है void)। "ब्रह्मांड" सेट के रूप में इसके बारे में सोचो; दुनिया में सभी मूल्यों के लिए कोई भी ऑपरेशन आम नहीं हैं , इसलिए प्रकार के मूल्य पर कोई वैध संचालन नहीं हैं void। इसे दूसरे तरीके से कहें, आपको बता रहा है कि ब्रह्मांड सेट से संबंधित कुछ भी आपको कोई जानकारी नहीं देता है - आप इसे पहले से ही जानते हैं। तो निम्नलिखित ध्वनि है:

(void)5;
(void)foo(17); // whatever foo(17) does

लेकिन नीचे असाइनमेंट नहीं है:

void raise();
void f(int y) {
    int x = y!=0 ? 100/y : raise(); // raise() returns void, so what should x be?
    cout << x << endl;
}

[[noreturn]]दूसरी ओर, कभी कभी कहा जाता है empty, Nothing, Bottomया Botऔर के तार्किक बराबर है झूठी । इसका कोई मूल्य नहीं है, और इस प्रकार की अभिव्यक्ति को किसी भी प्रकार के लिए (यानी उप-प्रकार) में डाला जा सकता है। यह खाली सेट है। ध्यान दें कि यदि कोई आपसे कहता है "अभिव्यक्ति फू का मूल्य () खाली सेट का है" तो यह बहुत जानकारीपूर्ण है - यह बताता है कि यह अभिव्यक्ति कभी भी अपने सामान्य निष्पादन को पूरा नहीं करेगी; यह गर्भपात, फेंक या लटका देगा। यह इसके ठीक विपरीत है void

तो निम्नलिखित का कोई मतलब नहीं है (छद्म-सी ++, क्योंकि noreturnप्रथम श्रेणी सी ++ प्रकार नहीं है)

void foo();
(noreturn)5; // obviously a lie; the expression 5 does "return"
(noreturn)foo(); // foo() returns void, and therefore returns

लेकिन नीचे दिए गए असाइनमेंट पूरी तरह से वैध हैं, क्योंकि throwकंपाइलर द्वारा वापस नहीं लौटने के लिए समझा जाता है:

void f(int y) {
    int x = y!=0 ? 100/y : throw exception();
    cout << x << endl;
}

एक आदर्श दुनिया में, आप ऊपर दिए noreturnगए फ़ंक्शन के लिए वापसी मान के रूप में उपयोग कर सकते हैं raise():

noreturn raise() { throw exception(); }
...
int x = y!=0 ? 100/y : raise();

अफसोस की बात है कि C ++ इसकी अनुमति नहीं देता है, शायद व्यावहारिक कारणों से। इसके बजाय यह आपको [[ noreturn ]]विशेषता का उपयोग करने की क्षमता देता है जो संकलक अनुकूलन और चेतावनी का मार्गदर्शन करने में मदद करता है।


5
कुछ भी नहीं करने के लिए डाली जा सकता है voidऔर voidकभी नहीं का मूल्यांकन करता है trueया falseया कुछ और।
क्लियर

5
जब मैं कहता हूं true, मेरा मतलब " trueप्रकार का मूल्य bool" नहीं है, लेकिन तर्क की समझ है, तो करी-हावर्ड पत्राचार
एलाजार

8
अमूर्त प्रकार का सिद्धांत जो किसी भाषा के प्रकार की प्रणाली में फिट नहीं होता है, उस भाषा के प्रकार के सिस्टम पर चर्चा करते समय अप्रासंगिक है। प्रश्न :-), प्रश्न, C ++ के बारे में है, न कि टाइप थ्योरी के बारे में।
क्लियर

8
(void)true;जवाब के रूप में पूरी तरह से मान्य है। void(true)कुछ पूरी तरह से अलग है, वाक्यात्मक रूप से। यह एक तर्क के रूप में voidएक निर्माता को बुलाकर प्रकार की एक नई वस्तु बनाने का प्रयास है true; यह अन्य कारणों के साथ, क्योंकि voidप्रथम श्रेणी नहीं है।
एलजार

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