जब noexcept सिर्फ एक फैशनेबल टैग नहीं, बल्कि 2025 में मुक्ति है

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

जब noexcept सिर्फ एक फैशन नहीं, बल्कि 2025 में आपका मुख्य उपकरण है

\n\n

कल्पना करें: आप C++ में कई वर्षों से लिख रहे हैं, कंपाइलर चुप है, कोड काम कर रहा है। लेकिन अचानक आप देखते हैं कि std::vector नए तत्वों को सम्मिलित करते समय किसी कारण से ऑब्जेक्ट्स को कॉपी कर रहा है, जबकि आपने स्पष्ट रूप से move-कंस्ट्रक्टर को परिभाषित किया था। परिचित दर्द? उस दुनिया में आपका स्वागत है जहाँ noexcept प्रदर्शन के भाग्य का फैसला करता है।

\n\n

Stack Overflow पर प्रश्न «When should I really use noexcept?» ने हजारों व्यूज एकत्र किए हैं - और यह व्यर्थ नहीं है। 2025 में, जब कंपाइलर और भी स्मार्ट हो गए हैं, और मानक पुस्तकालय गारंटी के लिए और भी अधिक मांग कर रहा है, noexcept का गलत उपयोग एक माइक्रो-ऑप्टिमाइज़ेशन से एक गंभीर त्रुटि में बदल जाता है। आइए समझते हैं कि यह स्पेसिफ़ायर कहाँ आपका सबसे अच्छा दोस्त है, और कहाँ यह अनावश्यक शोर है।

\n\n

संक्षिप्त परिचय: noexcept क्या है और इसकी आवश्यकता क्यों है?

\n\n

noexcept एक स्पेसिफ़ायर है जो कंपाइलर को बताता है: «यह फ़ंक्शन कभी भी अपवाद नहीं फेंकेगा»। C++17 में यह टाइप सिस्टम का हिस्सा बन गया, और C++20 में इसे ऑप्टिमाइज़ेशन पर और भी अधिक प्रभाव मिला।

\n\n

जब आप लिखते हैं:

\n
void safe_function() noexcept {\n    // कोड जो गारंटी के साथ अपवाद नहीं फेंकता\n}
\n\n

कंपाइलर को इस पर हरी झंडी मिलती है:

\n
    \n
  • अधिक कॉम्पैक्ट कोड उत्पन्न करना (स्टैक अनवाइंडिंग के ओवरहेड के बिना)
  • \n
  • कंटेनरों में move-सिमैंटिक्स का अनुकूलन
  • \n
  • वास्तविक अपवाद के मामले में std::terminate के लिए तर्क को सरल बनाना
  • \n
\n\n

लेकिन मुख्य बात - noexcept मानक कंटेनरों के व्यवहार को प्रभावित करता है। और यहीं सबसे आम समस्या छिपी है।

\n\n

नियम #1: Move-कंस्ट्रक्टर और move-असाइनमेंट ऑपरेटर noexcept होने चाहिए

\n\n

यह C++11 और उसके बाद के सभी मानकों का सुनहरा नियम है। यदि आपका move-कंस्ट्रक्टर noexcept के रूप में चिह्नित नहीं है, तो std::vector मेमोरी पुनः आवंटित करते समय तत्वों को स्थानांतरित करने के बजाय कॉपी करेगा। क्यों?

\n\n

क्योंकि std::vector को अपवादों की सख्त गारंटी सुनिश्चित करनी चाहिए। यदि move-ऑपरेशन अपवाद फेंक सकता है, तो कंटेनर मूल स्थिति में वापस नहीं आ सकेगा। कॉपी करना सुरक्षित है: यदि कॉपी विफल होती है, तो मूल ऑब्जेक्ट अप्रभावित रहता है।

\n\n

एक उदाहरण जो याद रखने योग्य है:

\n
#include <vector>\n#include <string>\n#include <iostream>\n\nstruct MyData {\n    std::string name;\n    \n    // Move-कंस्ट्रक्टर बिना noexcept के\n    MyData(MyData&& other) : name(std::move(other.name)) {\n        // सब ठीक है, लेकिन noexcept नहीं है!\n    }\n};\n\nint main() {\n    std::vector<MyData> vec;\n    MyData d1{"Alice"}, d2{"Bob"};\n    vec.push_back(std::move(d1));\n    vec.push_back(std::move(d2));  \n    // ध्यान दें: मेमोरी पुनः आवंटित करते समय \n    // तत्व कॉपी किए जाएंगे, स्थानांतरित नहीं!\n    std::cout << "आकार: " << vec.size() << std::endl;\n    return 0;\n}
\n\n

समाधान - noexcept जोड़ें:

\n
MyData(MyData&& other) noexcept : name(std::move(other.name)) {}
\n\n

निष्कर्ष: सभी move-ऑपरेशन जो अपवाद नहीं फेंकते (और वे आमतौर पर नहीं फेंकते, यदि वे मैन्युअल रूप से मेमोरी आवंटित नहीं करते), उन्हें noexcept के साथ चिह्नित किया जाना चाहिए। यह एक विकल्प नहीं है - यह प्रदर्शन के लिए एक आवश्यकता है।

\n\n

नियम #2: swap ऑपरेशन - noexcept के लिए एक और उम्मीदवार

\n\n

swap फ़ंक्शन अक्सर एल्गोरिदम और कंटेनरों में उपयोग किए जाते हैं। यदि swap अपवाद फेंक सकता है, तो कई एल्गोरिदम (जैसे, सॉर्टिंग) दक्षता खो देते हैं।

\n\n
class Buffer {\n    int* data;\n    size_t size;\npublic:\n    friend void swap(Buffer& a, Buffer& b) noexcept {\n        using std::swap;\n        swap(a.data, b.data);\n        swap(a.size, b.size);\n    }\n};
\n\n

यह क्यों महत्वपूर्ण है? क्योंकि std::sort, std::shuffle और अन्य

ब्लॉग

पुस्तक अनुशंसाएँ