C++ में कौन कौन: lvalue, rvalue, xvalue और अन्य "मान" (Values)

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

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

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

l, r, x, gl और pr अक्षरों के पीछे क्या छिपा है? C++ में मानों की श्रेणियों को समझें

\n\n

अगर आपने कभी C++ में कोड लिखते समय "cannot bind non-const lvalue reference to an rvalue" जैसी एरर देखी है, तो आप इस 'जादू' से पहले ही रूबरू हो चुके हैं। मानों की श्रेणियाँ — lvalue, rvalue, xvalue, glvalue और prvalue — सिर्फ एक अकादमिक वर्गीकरण नहीं हैं। यह वह नींव है जिस पर मूव सेमेन्टिक्स (move semantics) और परफेक्ट फॉरवर्डिंग (perfect forwarding) टिकी हुई है।

\n\n

आइए एक बार और हमेशा के लिए समझ लें कि हर अक्षर का क्या मतलब है, व्यवहार में उन्हें कैसे पहचानें, और क्यों इस ज्ञान के बिना आधुनिक, कुशल C++ लिखना असंभव है।

\n\n

संक्षिप्त इतिहास: ये पाँच शब्द कहाँ से आए?

\n\n

शुरुआत में, C के समय में, केवल दो अवधारणाएँ थीं: lvalue (बायाँ मान — जो असाइनमेंट के बाईं ओर आ सकता है) और rvalue (दायाँ मान — जो दाईं ओर आता है)। सब कुछ सरल था: वेरिएबल lvalue है, संख्या rvalue है।

\n\n

C++11 और मूव सेमेन्टिक्स के आगमन के साथ, यह सरल तस्वीर काम नहीं आई। rvalue रेफरेंस (&&) और 'मरने वाली' अस्थायी वस्तुओं (temporary objects) के बीच अंतर करने की आवश्यकता पैदा हुई। इस तरह नया वर्गीकरण जन्मा, जिसे C++ मानक पाँच श्रेणियों में वर्णित करता है।

\n\n

इस पदानुक्रम (टेक्स्ट के रूप में डायग्राम) पर एक नज़र डालें:

\n\n
        expression (अभिव्यक्ति)\n        /        \\\n   glvalue      rvalue\n   /      \\    /      \\\nlvalue   xvalue   prvalue
\n\n

इस तस्वीर को याद रखें — यह सबकी कुंजी है।

\n\n

lvalue (left value) — 'लंबे समय तक जीने वाली' वस्तुएँ

\n\n

lvalue एक ऐसी अभिव्यक्ति है जो मेमोरी में एक पता (address) रखने वाली वस्तु को संदर्भित करती है। ऐसी वस्तु अभिव्यक्ति के समाप्त होने के बाद गायब नहीं होती। आप इसका पता ले सकते हैं, इसे बदल सकते हैं, और यह अस्तित्व में बनी रहेगी।

\n\n

lvalue के उदाहरण:

\n
    \n
  • वेरिएबल का नाम: int x = 5; x — यह lvalue है।
  • \n
  • डीरेफरेंस किया गया पॉइंटर: *ptr।
  • \n
  • वेरिएबल का रेफरेंस: int& ref = x; ref।
  • \n
  • स्ट्रिंग लिटरल: "hello" (हाँ, यह lvalue है, भले ही कॉन्स्टेंट हो)।
  • \n
\n\n

कोड:

\n
int main() {\n    int a = 10;\n    int* p = &a;   // पता लेना ठीक है — a एक lvalue है\n    int& ref = a;  // lvalue का रेफरेंस\n\n    // &(a + 1);   // एरर! a+1 एक rvalue है, इसका कोई पता नहीं है\n    return 0;\n}
\n\n

rvalue (right value) — 'एक बार उपयोग होने वाले' मान

\n\n

rvalue एक ऐसी अभिव्यक्ति है जिसका मेमोरी में कोई स्थायी पता नहीं होता। यह केवल अभिव्यक्ति के मूल्यांकन के समय ही अस्तित्व में रहता है। आप इसका पता नहीं ले सकते (कुछ अपवादों को छोड़कर)।

\n\n

rvalue में शामिल हैं:

\n
    \n
  • लिटरल (स्ट्रिंग को छोड़कर): 42, 3.14f, true।
  • \n
  • अंकगणितीय संक्रियाओं के परिणाम: a + b।
  • \n
  • अस्थायी वस्तुएँ (temporary objects): std::string("temp")।
  • \n
  • लैम्ब्डा एक्सप्रेशन।
  • \n
\n\n

कोड:

\n
int foo() { return 5; }\n\nint main() {\n    int x = 42;       // 42 — rvalue\n    int y = x + 10;   // x+10 — rvalue\n    // int* p = &(x + 10); // एरर! rvalue का पता नहीं लिया जा सकता\n    return 0;\n}
\n\n

prvalue (pure rvalue) — 'शुद्ध' rvalue

\n\n

prvalue C++98 का क्लासिक rvalue है। यह एक अस्थायी मान है जिसका कोई नाम नहीं है और यह मेमोरी से बंधा नहीं है। बोलचाल की भाषा में हम आमतौर पर prvalue को ही rvalue कहते हैं।

\n\n

prvalue के उदाहरण:

\n
    \n
  • संख्याएँ, एनुमरेशन, ऑपरेटरों के परिणाम।
  • \n
  • फंक्शन कॉल जो गैर-रेफरेंस लौटाता है: std::to_string(123)।
  • \n
  • स्पष्ट रूप से बनाई गई अस्थायी वस्तु: MyClass()।
  • \n
\n\n

xvalue (expiring value) — 'मरने वाली' वस्तुएँ

\n\n

यहाँ से सबसे दिलचस्प चीज़ शुरू होती है। xvalue एक ऐसी वस्तु है जो जल्द ही नष्ट होने वाली है, लेकिन इसके संसाधनों को अभी भी 'बचाया' (मूव किया) जा सकता है। यह एक पुल की तरह है

ब्लॉग

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