प्रतिनिधि इंटरव्यू विषय

C++26 Contracts: आप preconditions, postconditions और contract_assert को सुरक्षित रूप से कैसे शिप करते हैं?

कोडिंगकठिन
Offer.cc संपादकीय टीमप्रकाशित अपडेट किया गया

प्रश्न

आप pre, post और contract_assert की व्याख्या कैसे करते हैं और कंपाइलर सपोर्ट अधूरा होने के दौरान मौजूदा assert के उपयोग को कैसे माइग्रेट करते हैं?

प्रॉम्प्ट और दायरा

आप एक ऑर्डर लाइब्रेरी के ओनर हैं और API preconditions, postconditions और फ़ंक्शन-बॉडी invariants को व्यक्त करने के लिए C++26 Contracts का उपयोग करना चाहते हैं। pre, post और contract_assert की सेमांटिक सीमाओं, मूल्यांकन मोड, उल्लंघन प्रबंधन, और मौजूदा assert उपयोग से माइग्रेशन पाथ की व्याख्या करें जो अविश्वसनीय इनपुट के सत्यापन को न हटाए। कंपाइलर सपोर्ट अधूरा होने के दौरान एक रिलीज़ रणनीति भी शामिल करें।

इंटरव्यूअर क्या टेस्ट कर रहा है

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

स्पष्टीकरण के प्रश्न

  1. क्या कॉलर विश्वसनीय लाइब्रेरी कोड हैं या सीधे नेटवर्क-अनुरोध हैंडलर हैं?
  2. क्या प्रोडक्शन को उल्लंघन का निरीक्षण करना चाहिए, प्रक्रिया को समाप्त करना चाहिए, या अनुरोध को अलग करके जारी रखना चाहिए?
  3. कौन सा कंपाइलर, मानक-लाइब्रेरी संस्करण और ABI रिलीज़ चक्र दायरे में हैं?

30-सेकंड का उत्तर ढांचा

ज़िम्मेदारी से शुरुआत करें: pre बताता है कि कॉलर को क्या संतुष्ट करना चाहिए, post बताता है कि कॉली रिटर्न पर क्या वादा करता है, और contract_assert एक स्थानीय फ़ंक्शन-बॉडी कॉन्ट्रैक्ट बताता है। फिर बताएं कि प्रेडिकेट्स में कोई साइड-इफ़ेक्ट नहीं होने चाहिए क्योंकि एक कार्यान्वयन मूल्यांकन को छोड़ सकता है या दोहरा सकता है; उल्लंघन एक हैंडलर और परिनियोजन नीति के माध्यम से जाते हैं। अंत में, अविश्वसनीय इनपुट के लिए स्पष्ट सत्यापन रखें और माइग्रेशन के लिए फीचर डिटेक्शन, एक कंपाइलर मैट्रिक्स और कैनरी का उपयोग करें।

गहन उत्तर

1. कॉन्ट्रैक्ट लेयर्स स्थापित करें

Preconditions कॉलर की ज़िम्मेदारी हैं; postconditions कॉली की ज़िम्मेदारी हैं। वे कंपोज़ेबल API बाधाओं को व्यक्त करते हैं जैसे कि सकारात्मक क्षमता या ऑर्डरिंग गारंटी। फ़ंक्शन-बॉडी contract_assert एक स्थानीय इनवेरिएंट या एल्गोरिदम-चरण धारणा को व्यक्त करता है। तीनों को कोड समीक्षा में पठनीय होना चाहिए और रिकवरी नीति से अलग रखा जाना चाहिए।

2. प्रेडिकेट्स को साइड-इफ़ेक्ट मुक्त रखें

एक प्रेडिकेट को केवल स्थिति पढ़नी चाहिए और एक बूलियन की गणना करनी चाहिए। इसके अंदर काउंटरों को न बढ़ाएं, कैश को म्यूटेट न करें, संसाधनों को रिलीज़ न करें, या वन-शॉट रैंडमनेस पर निर्भर न रहें। C++26 कॉन्ट्रैक्ट सेमांटिक्स विभिन्न मूल्यांकन मोड की अनुमति देते हैं: कुछ मूल्यांकन को छोड़ सकते हैं और अन्य एक से अधिक बार मूल्यांकन कर सकते हैं। साइड-इफ़ेक्ट्स के कारण सही-प्रोग्राम का व्यवहार बिल्ड कॉन्फ़िगरेशन पर निर्भर हो जाएगा।

cpp
int withdraw(Account& a, int amount)
  pre (amount > 0)
  pre (amount <= a.balance())
  post (a.balance() == old_balance - amount);
{
  contract_assert(a.is_open());
  return a.debit(amount);
}

स्निपेट में old_balance एक डिज़ाइन समस्या पर प्रकाश डालता है; C++26 एक सामान्य पोस्टकंडीशन कैप्चर प्रदान नहीं करता है, इसलिए old(...) सिंटैक्स मानकर न चलें। यदि पुराने मान की आवश्यकता है, तो इसे फ़ंक्शन में स्पष्ट रूप से सहेजें और पुष्टि करें कि सहेजना व्यावसायिक सेमांटिक्स को नहीं बदलता है, या बाद के मानक विस्तार की प्रतीक्षा करें।

3. मूल्यांकन और उल्लंघन प्रबंधन चुनें

Observe और enforce जैसे मोड के लिए व्यवहार परिभाषित करें। विकास और परीक्षण डायग्नोस्टिक्स एकत्र कर सकते हैं; एक महत्वपूर्ण सेवा enforcement के तहत तेज़ी से विफल (fail fast) हो सकती है; एक अनुरोध सीमा एक विफलता को एक अवलोकन योग्य, पृथक परिणाम में बदल सकती है। यह वादा न करें कि उल्लंघन हमेशा थ्रो करता है: व्यवहार कार्यान्वयन और बिल्ड कॉन्फ़िगरेशन पर निर्भर करता है। हैंडलर को कॉन्ट्रैक्ट स्थान, अनुरोध सहसंबंध ID और संस्करण रिकॉर्ड करना चाहिए, जबकि उसी कॉन्ट्रैक्ट पाथ में पुनरावर्ती (recursive) प्रवेश से बचना चाहिए।

4. सीमा पर इनपुट सत्यापन बनाए रखें

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

5. माइग्रेशन और रिलीज़ की योजना बनाएं

फीचर मैक्रो और कंपाइलर संस्करण द्वारा एक क्षमता मैट्रिक्स बनाएं, सिंटैक्स, हैंडलर, डिबग जानकारी और अनुकूलित बिल्ड का अलग-अलग परीक्षण करें। परीक्षणों और कैनरीज़ में observe मोड सक्षम करें, उल्लंघन दर और ओवरहेड की तुलना करें, फिर धीरे-धीरे enforcement बढ़ाएं। पारंपरिक assert में मैक्रो विस्तार, NDEBUG और साइड-इफ़ेक्ट धारणाएं होती हैं जिन्हें यांत्रिक रूप से समान नहीं माना जा सकता है; प्रत्येक उपयोग का ऑडिट करें, विफलता सेमांटिक्स को सुरक्षित रखें, और जब समान रिपोर्टिंग की आवश्यकता हो तो एक एडेप्टर का उपयोग करें।

उच्च-गुणवत्ता वाला नमूना उत्तर

मैं कॉन्ट्रैक्ट्स को निष्पादन योग्य डिज़ाइन बाधाओं के रूप में मानता हूं, न कि इनपुट सत्यापन या अपवाद प्रणाली के रूप में। pre कॉलर को बाध्य करता है, post कॉली को बाध्य करता है, और contract_assert एक फ़ंक्शन-बॉडी इनवेरिएंट को बाध्य करता है। प्रत्येक प्रेडिकेट केवल-पढ़ने के लिए रहता है क्योंकि एक कार्यान्वयन मूल्यांकन को छोड़ सकता है या दोहरा सकता है, इसलिए मैं I/O, काउंटर म्यूटेशन और संसाधन रिलीज़ को प्रतिबंधित करता हूं। उल्लंघन एक हैंडलर के माध्यम से जाते हैं जो संरचित डायग्नोस्टिक्स उत्सर्जित करता है; बिल्ड नीति तब अवलोकन, प्रवर्तन, या फ़ेल-फ़ास्ट व्यवहार चुनती है, और कोड अपवाद मानकर नहीं चलता है। अनुरोध सीमा अभी भी प्रमाणीकरण, प्राधिकरण और अविश्वसनीय-डेटा जांच करती है। माइग्रेशन के लिए मैं एक कंपाइलर क्षमता मैट्रिक्स बनाता हूं, परीक्षणों और कैनरीज़ से शुरू करता हूं, और धीरे-धीरे enforcement बढ़ाता हूं; मैं assert को यांत्रिक रूप से बदलने के बजाय NDEBUG और मैक्रो साइड-इफ़ेक्ट्स का ऑडिट करता हूं। यह ऑनलाइन रिकवरी को गैर-समान कार्यान्वयन व्यवहार पर निर्भर किए बिना स्थिर आंतरिक जांच प्रदान करता है।

सामान्य गलतियाँ

  • प्रत्येक इनपुट के लिए pre को एक पूर्ण सुरक्षा जांच मानना।
  • प्रेडिकेट्स के अंदर लॉगिंग करना, मेट्रिक्स बढ़ाना, या ऑब्जेक्ट्स को म्यूटेट करना।
  • यह दावा करना कि उल्लंघन को मोड की परवाह किए बिना थ्रो करना चाहिए या समाप्त होना चाहिए।
  • प्रत्येक assert को contract_assert से बदलना और NDEBUG, मैक्रो तर्कों या साइड-इफ़ेक्ट्स को छोड़ देना।
  • एक गैर-मौजूद सामान्य old(...) सिंटैक्स के साथ C++26 पोस्टकंडीशन का वर्णन करना।

फॉलो-अप और प्रतिक्रियाएं

क्या होगा यदि इंटरव्यूअर पूछे, "हर जगह एक्सेप्शन का उपयोग क्यों न करें?"

कॉन्ट्रैक्ट्स कॉलर और कॉली की ज़िम्मेदारी बताते हैं और समीक्षा और बिल्ड नीति में भाग ले सकते हैं; अपवाद नियंत्रण प्रवाह और रिकवरी को परिभाषित करते हैं। वे एक-दूसरे के पूरक हैं और विनिमेय नहीं हैं।

क्या होगा यदि बार-बार प्रेडिकेट मूल्यांकन बहुत महंगा हो?

प्रेडिकेट्स को केवल-पढ़ने के लिए और सस्ता रखें, फिर प्रत्येक बिल्ड मोड को मापें। महंगे डायग्नोस्टिक्स को एक कॉन्ट्रैक्ट में साइड-इफ़ेक्ट छिपाने के बजाय एक स्पष्ट पाथ पर रखें।

क्या होगा यदि वे पूछें कि क्या वर्चुअल फ़ंक्शन सीधे कॉन्ट्रैक्ट ले जा सकते हैं?

C++26 की यहाँ एक सीमा है: WG21 रोडमैप वर्चुअल-फ़ंक्शन सपोर्ट को बाद के विस्तार के रूप में सूचीबद्ध करता है। भविष्य के प्रस्ताव को मौजूदा C++26 व्यवहार के रूप में प्रस्तुत करने के बजाय लक्ष्य कंपाइलर और मानक संस्करण की जांच करें।

सार्वजनिक स्रोत

संबंधित प्रश्न

संबंधित इंटरव्यू टूल

कोडिंग प्रॉम्प्ट के लिए स्क्रीनशॉट का उपयोग करें

समस्या को कैप्चर करें, फिर क्रम से प्रतिबंधों (constraints), समाधान, कोड, एज केस और जटिलता पर काम करें।

टूल देखें