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

C++ इंटरव्यू: std::mdspan लेआउट, लाइफटाइम और परफॉरमेंस को कैसे संभालता है?

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

प्रश्न

एक ऐसा टू-डायमेंशनल मैट्रिक्स इंटरफ़ेस डिज़ाइन करें जो कॉपी करने से बचे, रो-मेजर और कॉलम-मेजर डेटा को सपोर्ट करे, और std::mdspan के लेआउट, लाइफटाइम व परफॉरमेंस जोखिमों की व्याख्या करे।

प्रश्न और परिदृश्य

एक ऐसा टू-डायमेंशनल मैट्रिक्स इंटरफ़ेस डिज़ाइन करें जो कॉपी करने से बचे, रो-मेजर और कॉलम-मेजर डेटा को सपोर्ट करे, और std::mdspan के लेआउट, लाइफटाइम व परफॉरमेंस जोखिमों की व्याख्या करे।

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

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

  • क्या आप जानते हैं कि std::mdspan एक नॉन-ओनिंग मल्टीडायमेंशनल व्यू है और यह एलिमेंट्स को एलोकेट या रिलीज़ नहीं करता है।
  • क्या आप layout_right, layout_left और कस्टम स्ट्राइड्स के बीच मैपिंग के अंतर को समझा सकते हैं।
  • क्या आप बैकिंग बफ़र के लाइफटाइम, ग्रोथ या रिलोकेशन से उत्पन्न होने वाले डैंगलिंग-व्यू (dangling-view) जोखिमों की पहचान कर सकते हैं।
  • क्या आप लेआउट चयन, ट्रैवर्सल क्रम और कैश लोकैलिटी को जोड़कर देख सकते हैं।
  • क्या आप स्टैटिक एक्सटेंट्स, डायनामिक एक्सटेंट्स और रनटाइम चेक्स के साथ एक इंटरफ़ेस कॉन्ट्रैक्ट व्यक्त कर सकते हैं।

उत्तर देने से पहले स्पष्टीकरण हेतु प्रश्न

  1. बैकिंग डेटा का ओनर कौन है, और क्या व्यू के मौजूद रहने के दौरान कॉलर कंटेनर को ग्रो या मूव कर सकता है?
  2. क्या रो और कॉलम एक्सटेंट्स कंपाइल-टाइम पर ज्ञात हैं, और क्या एक ही फ़ंक्शन को कई शेप्स स्वीकार करने होंगे?
  3. क्या इनपुट रो-मेजर है, कॉलम-मेजर है, या पैडेड और टाइल्ड है?
  4. क्या परफॉरमेंस का लक्ष्य सीक्वेंशियल स्कैनिंग, रैंडम एक्सेस, या विभिन्न एक्ज़ीक्यूशन डिवाइसेस में पोर्टेबिलिटी है?

30-सेकंड उत्तर फ्रेमवर्क

mdspan एक C++23 नॉन-ओनिंग मल्टीडायमेंशनल ऐरे रेफरेंस है। यह एक डेटा हैंडल, एक्सटेंट्स, और इंडेक्स से ऑफ़सेट तक एक मैपिंग स्टोर करता है। सबसे पहले ओनर को लाइव और एड्रेस-स्टेबल रखें। फिर layout_right (राइटमोस्ट डायमेंशन में यूनिट स्ट्राइड, सामान्य C-स्टाइल रो-मेजर व्यवहार), layout_left (लेफ्टमोस्ट डायमेंशन में यूनिट स्ट्राइड, सामान्य कॉलम-मेजर व्यवहार), या layout_stride चुनें। स्टैटिक एक्सटेंट्स को टाइप में एन्कोड किया जा सकता है; डायनामिक एक्सटेंट्स dextents का उपयोग करते हैं। बफ़र-साइज़ और लाइफटाइम कॉन्ट्रैक्ट का स्वामित्व अभी भी कॉलर के पास होता है। ट्रैवर्सल को सन्निहित (contiguous) डायमेंशन का पालन करना चाहिए, क्योंकि एक मिसमैच्ड वॉक सही हो सकता है लेकिन कैश-अनफ्रेंडली होता है।

चरण-दर-चरण विस्तृत उत्तर

1. व्यू को कंटेनर से अलग करें

mdspan वन-डायमेंशनल span का मल्टीडायमेंशनल समकक्ष है: यह इंडेक्सिंग, एक्सटेंट्स और मैपिंग प्रदान करता है, लेकिन यह एलिमेंट्स का मालिक नहीं होता है। यहाँ ओनर storage है:

cpp
#include <mdspan>
#include <vector>

std::size_t rows = 3;
std::size_t cols = 4;
std::vector<float> storage(rows * cols);
using matrix_view = std::mdspan<float, std::dextents<std::size_t, 2>>;
matrix_view matrix(storage.data(), rows, cols);
matrix(1, 2) = 7.0f;

storage के नष्ट, मूव, या री-एलोकेट होने के बाद, matrix का उपयोग नहीं किया जा सकता है। इंटरफ़ेस को उन ऑपरेशन्स को प्रतिबंधित करना चाहिए या केवल ऐसा पॉइंटर और साइज़ स्वीकार करना चाहिए जिसका स्टोरेज कॉल के दौरान स्थिर रहे।

2. लेआउट मैपिंग समझाएं

लेआउट पॉलिसी लॉजिकल कोऑर्डिनेट्स को लीनियर ऑफ़सेट में मैप करती है। layout_right सबसे दाहिने एक्सटेंट को सन्निहित (contiguous) बनाता है, इसलिए टू-डायमेंशनल वॉक आमतौर पर पहले row फिर column को स्कैन करता है। layout_left सबसे बाईं ओर के एक्सटेंट को सन्निहित बनाता है। layout_stride पैडिंग, ट्रांसपोज़्ड व्यूज़, स्लाइसेस या टाइल्ड स्टोरेज को दर्शा सकता है।

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

3. स्टैटिक या डायनामिक एक्सटेंट्स चुनें

चार-कॉलम मैट्रिक्स जैसा एक इनवेरिएंट टाइप में एन्कोड किया जा सकता है:

cpp
using four_column_view = std::mdspan<
    float,
    std::extents<std::size_t, std::dynamic_extent, 4>>;

रो काउंट रनटाइम डेटा है जबकि कॉलम काउंट टाइप-लेवल कॉन्ट्रैक्ट है। पूरी तरह से डायनामिक शेप के लिए, टू-डायमेंशनल dextents एलियास का उपयोग करें। किसी भी स्थिति में, निर्माण से पहले जांच लें कि rows * cols वास्तविक बफ़र में फिट बैठता है और मल्टीप्लिकेशन ओवरफ्लो से बचाव करें।

4. परफॉरमेंस दावों को स्ट्राइड मापों में बदलें

दो लूप दिखाएं: एक layout_right व्यू को पंक्तियों द्वारा स्कैन करें ताकि इनर कॉलम इंडेक्स सन्निहित रहे; layout_left के लिए, इसके विपरीत क्रम अपनाएं। matrix.mapping().stride(i) या मैपिंग के आवश्यक स्पैन साइज़ का निरीक्षण करें ताकि "कैश फ्रेंडली" एक मापने योग्य परिकल्पना बन जाए। निश्चित डेटा साइज़ और कंपाइलर विकल्पों के साथ सीक्वेंशियल, रिवर्स और स्ट्राइडेड वॉक्स का बेंचमार्क करें।

5. बाउंड्स और एक्सेसर सीमा तय करें

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

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

मैं मैट्रिक्स की ओनरशिप वेक्टर, ऐरे या कॉलर-मैनेज्ड बफ़र के पास छोड़ूंगा और एल्गोरिदम को एक लाइटवेट व्यू के रूप में mdspan पास करूंगा। निर्माण के समय, दोनों एक्सटेंट्स को रिकॉर्ड करें और उनके गुणनफल को वैलिडेट करें। व्यू को स्टोरेज से अधिक समय तक नहीं टिकना चाहिए और न ही ऐसे किसी ऑपरेशन के पार जाना चाहिए जो वेक्टर को री-एलोकेट करता हो। लेआउट पॉलिसी वास्तविक स्ट्राइड से मेल खानी चाहिए: layout_right राइटमोस्ट-डायमेंशन-कॉन्टिग्यूअस C-स्टाइल डेटा के लिए उपयुक्त है, layout_left कॉलम-कॉन्टिग्यूअस डेटा के लिए उपयुक्त है, और layout_stride पैडिंग को संभालता है। लूप का क्रम सन्निहित डायमेंशन का अनुसरण करता है, ताकि एक सही मैपिंग धीमी स्ट्राइडेड वॉक न बन जाए। मैं डैंगलिंग व्यूज़ को पकड़ने के लिए AddressSanitizer, मैपिंग को सत्यापित करने के लिए डायमेंशन और स्ट्राइड असर्शन्स, और लेआउट्स व लूप ऑर्डर्स की तुलना करने के लिए एक फिक्स्ड बेंचमार्क का उपयोग करूंगा।

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

  • mdspan को एक ओनिंग मैट्रिक्स कंटेनर मानना और वास्तविक ओनर को भूल जाना।
  • वास्तविक स्ट्राइड की जांच किए बिना बाहरी डेटा पर डिफ़ॉल्ट लेआउट लागू करना।
  • गति को ट्रैवर्सल क्रम और सन्निहित डायमेंशन से जोड़े बिना यह कहना कि "रो-मेजर तेज़ है"।
  • वेक्टर ग्रोथ, रिलोकेशन या अस्थायी ऐरे के समाप्त होने को अनदेखा करना।
  • बफ़र क्षमता और मल्टीप्लिकेशन ओवरफ्लो को नज़रअंदाज़ करते हुए केवल दो एक्सटेंट्स की जांच करना।
  • यह दावा करना कि mdspan स्वचालित रूप से बाउंड्स की जांच करता है या डेटा को ट्रांसपोज़ करता है।

फॉलो-अप प्रश्न और उत्तर

mdspan, span से किस प्रकार भिन्न है?

span एक सन्निहित (contiguous) वन-डायमेंशनल रेंज का वर्णन करता है। mdspan अतिरिक्त रूप से मल्टीडायमेंशनल एक्सटेंट्स, एक लेआउट मैपिंग और एक एक्सेसर रखता है, जिससे यह मल्टीडायमेंशनल कोऑर्डिनेट्स को लीनियर ऑफ़सेट में मैप कर सकता है। दोनों में से कोई भी अंतर्निहित एलिमेंट्स का मालिक नहीं होता है।

आप layout_stride कब चुनेंगे?

इसका उपयोग पैडिंग, ट्रांसपोज़्ड व्यूज़, स्लाइसेस या गैर-सन्निहित डायमेंशन्स के लिए करें। पहले प्रत्येक वास्तविक स्ट्राइड को स्थापित करें, फिर सत्यापित करें कि सबसे बड़ा मैप्ड ऑफ़सेट बफ़र के भीतर रहता है।

क्या कोई फ़ंक्शन एक व्यू रिटर्न कर सकता है?

हाँ, यदि लौटाए गए व्यू के पूरे उपयोग के दौरान ओनर लाइव और एड्रेस-स्टेबल रहता है। कभी भी किसी लोकल वेक्टर का व्यू रिटर्न न करें, और जब तक व्यू उपयोग में हो तब तक री-एलोकेशन की अनुमति न दें।

आप कैसे साबित करेंगे कि लेआउट का विकल्प मददगार है?

स्ट्राइड्स और एक्सेस ऑर्डर को रिकॉर्ड करें, फिर सन्निहित और स्ट्राइडेड वॉक्स के लिए थ्रूपुट, कैश काउंटर्स और स्केलिंग को मापें। कंपाइलर, ऑप्टिमाइज़ेशन लेवल और इनपुट डिस्ट्रीब्यूशन को स्थिर रखें; केवल टाइप का नाम कोई प्रमाण नहीं है।

स्रोत: cppreference std::mdspan और हेडर प्रविष्टियाँ, WG21 P0009R6 “mdspan: A Non-Owning Multidimensional Array Reference,” और Verve AI की मल्टीडायमेंशनल-ऐरे इंटरव्यू चर्चा (पूर्ण URLs meta.json में दर्ज हैं)।

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

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

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

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

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

टूल देखें