C++ में त्रुटि प्रबंधन: try/catch से आधुनिक दृष्टिकोणों तक
\n\nC++ में अपवाद तंत्र एक शक्तिशाली लेकिन गहन समझ की आवश्यकता वाला उपकरण है। जबकि try/catch का बुनियादी उपयोग अधिकांश डेवलपर्स को ज्ञात है, पेशेवर त्रुटि प्रबंधन में बहुत कुछ शामिल है: अपवाद सुरक्षा गारंटी से लेकर बिना अपवाद के वैकल्पिक रणनीतियों तक। इस लेख में, हम आधुनिक C++ में त्रुटियों के साथ काम करने की उन्नत तकनीकों का विश्लेषण करेंगे।
1. अपवाद सुरक्षा गारंटी: विश्वसनीय कोड की नींव
\n\nकोई भी फ़ंक्शन जो अपवाद फेंक सकता है, उसे तीन सुरक्षा गारंटियों में से एक प्रदान करनी चाहिए:
\n\n- \n
- बुनियादी गारंटी (Basic Guarantee): अपवाद की स्थिति में, ऑब्जेक्ट के इनवेरिएंट संरक्षित रहते हैं, कोई संसाधन लीक नहीं होता। ऑब्जेक्ट अप्रत्याशित लेकिन मान्य स्थिति में हो सकता है। \n
- सख्त गारंटी (Strong Guarantee): ऑपरेशन या तो पूरी तरह से निष्पादित होता है, या प्रोग्राम की स्थिति अपरिवर्तित रहती है (परमाणुता)। यह copy-and-swap मुहावरे के माध्यम से प्राप्त किया जाता है। \n
- कोई अपवाद न होने की गारंटी (Noexcept Guarantee): फ़ंक्शन कभी भी अपवाद नहीं फेंकता। डिस्ट्रक्टर, मूव-ऑपरेशन और कंटेनरों में उपयोग किए जाने वाले ऑपरेशनों के लिए महत्वपूर्ण। \n
// copy-and-swap के माध्यम से सख्त गारंटी का उदाहरण\nclass Vector {\n int* data;\n size_t sz, cap;\npublic:\n void push_back(int value) {\n if (sz == cap) {\n // 1. एक प्रतिलिपि बनाएँ\n Vector tmp(*this);\n // 2. प्रतिलिपि को संशोधित करें (अपवाद फेंक सकता है)\n tmp.reserve(cap * 2);\n // 3. अदला-बदली (noexcept!)\n swap(tmp);\n }\n data[sz++] = value; // noexcept\n }\n \n void swap(Vector& other) noexcept {\n std::swap(data, other.data);\n std::swap(sz, other.sz);\n std::swap(cap, other.cap);\n }\n};\n\n2. संसाधन प्रबंधन के आधार के रूप में RAII
\n\nRAII (Resource Acquisition Is Initialization) मुहावरा केवल स्मार्ट पॉइंटर्स नहीं है। यह एक मौलिक सिद्धांत है जो अपवादों के दौरान संसाधन लीक से बचने में मदद करता है:
\n\n- \n
- संसाधन कंस्ट्रक्टर में प्राप्त किया जाता है \n
- डिस्ट्रक्टर में मुक्त किया जाता है (जो डिफ़ॉल्ट रूप से
noexceptहोता है) \n - डिस्ट्रक्टर में अपवाद — UB (अपरिभाषित व्यवहार) \n
// फ़ाइल डिस्क्रिप्टर के लिए RAII-रैपर\nclass FileDescriptor {\n int fd;\npublic:\n explicit FileDescriptor(const char* path) \n : fd(open(path, O_RDONLY)) {\n if (fd == -1) throw std::runtime_error("Failed to open file");\n }\n \n ~FileDescriptor() noexcept {\n if (fd != -1) close(fd);\n }\n \n // कॉपी करना प्रतिबंधित करें, मूव की अनुमति दें\n FileDescriptor(FileDescriptor&& other) noexcept : fd(other.fd) {\n other.fd = -1;\n }\n};\n\n3. अपवादों के आधुनिक विकल्प: std::optional और std::expected
\n\nसभी त्रुटियों को अपवादों के माध्यम से संभालना आवश्यक नहीं है। अपेक्षित त्रुटियों (गलत इनपुट, डेटा की अनुपलब्धता) के लिए, रैपर प्रकारों का उपयोग करना बेहतर है:
\n\n#include <optional>\n#include <expected> // C++23\n\n// std::optional — वैकल्पिक मानों के लिए\nstd::optional<int> safe_divide(int a, int b) {\n if (b == 0) return std::nullopt;\n return a / b;\n}\n\n// std::expected — जानकारी के साथ त्रुटियों के लिए (C++23)\nstd::expected<double, std::string> sqrt_checked(double x) {\n if (x < 0) return std::unexpected("Negative input");\n return std::sqrt(x);\n}\n\n// उपयोग\nauto result = safe_divide(10, 0);\nif (result) {\n std::cout << *result;\n} else {\n std::cout << "Division by zero";\n}\n\n4. noexcept: विनिर्देश और अनुकूलन
\n\nnoexcept विनिर्देशक केवल दस्तावेज़ीकरण नहीं है। यह प्रदर्शन को प्रभावित करता है और