C++
मूल्य श्रेणियाँ
खोज…
मूल्य श्रेणी अर्थ
C ++ में अभिव्यक्तियां उन भावों के परिणाम के आधार पर एक विशेष मान श्रेणी में दी गई हैं। अभिव्यक्ति के लिए मूल्य श्रेणियां C ++ फ़ंक्शन अधिभार रिज़ॉल्यूशन को प्रभावित कर सकती हैं।
मूल्य श्रेणियां एक अभिव्यक्ति के बारे में दो महत्वपूर्ण-लेकिन-अलग गुण निर्धारित करती हैं। एक संपत्ति यह है कि क्या अभिव्यक्ति की पहचान है। एक अभिव्यक्ति की पहचान होती है यदि यह एक ऐसी वस्तु को संदर्भित करता है जिसमें एक चर नाम होता है। चर नाम अभिव्यक्ति में शामिल नहीं हो सकता है, लेकिन ऑब्जेक्ट अभी भी एक हो सकता है।
अन्य संपत्ति यह है कि क्या यह अभिव्यक्ति के मूल्य से अंतर्निहित कदम के लिए कानूनी है। या अधिक विशेष रूप से, चाहे अभिव्यक्ति, जब एक फ़ंक्शन पैरामीटर के रूप में उपयोग किया जाता है, आर-वैल्यू पैरामीटर प्रकारों के लिए बाध्य होगा या नहीं।
C ++ 3 मान श्रेणियों को परिभाषित करता है जो इन गुणों के उपयोगी संयोजन का प्रतिनिधित्व करते हैं: lvalue (पहचान के साथ अभिव्यक्ति लेकिन चल नहीं), xvalue (पहचान के साथ अभिव्यक्ति जो चल सकने योग्य हैं), और prvalue (पहचान के बिना चलने वाले भाव)। C ++ में ऐसी अभिव्यक्तियाँ नहीं हैं जिनकी कोई पहचान नहीं है और उन्हें स्थानांतरित नहीं किया जा सकता है।
C ++ दो अन्य मूल्य श्रेणियों को परिभाषित करता है, जिनमें से प्रत्येक पूरी तरह से इन गुणों में से एक पर आधारित है: glvalue (पहचान के साथ अभिव्यक्ति) और rvalue (अभिव्यक्तियाँ जो इससे स्थानांतरित की जा सकती हैं)। ये पूर्व श्रेणियों के उपयोगी समूहों के रूप में कार्य करते हैं।
यह ग्राफ चित्रण के रूप में कार्य करता है:
prvalue
एक प्रचलन (शुद्ध-रूवल) अभिव्यक्ति एक अभिव्यक्ति है जिसमें पहचान की कमी होती है, जिसका मूल्यांकन आमतौर पर किसी वस्तु को शुरू करने के लिए किया जाता है, और जिसे अंतर्निहित रूप से स्थानांतरित किया जा सकता है। इनमें शामिल हैं, लेकिन इन तक सीमित नहीं हैं:
- अभिव्यक्तियाँ जो अस्थायी वस्तुओं का प्रतिनिधित्व करती हैं, जैसे
std::string("123")
। - एक फ़ंक्शन कॉल अभिव्यक्ति जो एक संदर्भ वापस नहीं करता है
- एक शाब्दिक (एक स्ट्रिंग शाब्दिक को छोड़कर - वे अंतराल हैं), जैसे
1
,true
,0.5f
, या'a'
- एक लंबोदर अभिव्यक्ति
इन अभिव्यक्तियों पर अंतर्निहित एड्रेसऑफ़ ऑपरेटर ( &
) लागू नहीं किया जा सकता है।
XValue
एक xvalue (eXpiring मूल्य) अभिव्यक्ति एक अभिव्यक्ति है जिसकी पहचान है और एक वस्तु का प्रतिनिधित्व करता है जिसे अंतर्निहित रूप से स्थानांतरित किया जा सकता है। Xvalue अभिव्यक्तियों के साथ सामान्य विचार यह है कि जिस वस्तु का वे प्रतिनिधित्व करते हैं, वह जल्द ही नष्ट होने वाली है (इसलिए "eXpiring" भाग), और इसलिए उनसे स्पष्ट रूप से आगे बढ़ना ठीक है।
दिया हुआ:
struct X { int n; };
extern X x;
4; // prvalue: does not have an identity
x; // lvalue
x.n; // lvalue
std::move(x); // xvalue
std::forward<X&>(x); // lvalue
X{4}; // prvalue: does not have an identity
X{4}.n; // xvalue: does have an identity and denotes resources
// that can be reused
lvalue
एक लवल्यू एक्सप्रेशन एक ऐसी अभिव्यक्ति है जिसकी पहचान है, लेकिन इससे अलग नहीं किया जा सकता है। इनमें वे अभिव्यक्तियाँ हैं जो एक चर नाम, फ़ंक्शन नाम से बनी होती हैं, जो अंतर्निहित डाइरेक्टर ऑपरेटर का उपयोग करती हैं और ऐसे भाव होते हैं जो लवलीन के संदर्भ को संदर्भित करते हैं।
ठेठ लवल्यू बस एक नाम है, लेकिन लवल्यूस अन्य स्वादों में भी आ सकते हैं:
struct X { ... };
X x; // x is an lvalue
X* px = &x; // px is an lvalue
*px = X{}; // *px is also an lvalue, X{} is a prvalue
X* foo_ptr(); // foo_ptr() is a prvalue
X& foo_ref(); // foo_ref() is an lvalue
इसके अतिरिक्त, जबकि अधिकांश शाब्दिक (उदाहरण 4
, 'x'
, आदि) प्रचलन हैं, स्ट्रिंग शाब्दिक हैं।
glvalue
एक ग्लव्यू (एक "सामान्यीकृत लैवल्यू") अभिव्यक्ति कोई भी अभिव्यक्ति है जिसकी पहचान होती है, भले ही इसे वहां से ले जाया जा सके या नहीं। इस श्रेणी में लवल्यूज़ (ऐसे भाव शामिल होते हैं जिनकी पहचान होती है, लेकिन उनसे स्थानांतरित नहीं की जा सकती) और xvalues (ऐसे व्यंजक जिनकी पहचान होती है, और जिनसे स्थानांतरित किया जा सकता है), लेकिन प्रचलन (बिना पहचान के भाव) को शामिल नहीं करता है।
यदि किसी अभिव्यक्ति का नाम है , तो यह एक चमक है:
struct X { int n; };
X foo();
X x;
x; // has a name, so it's a glvalue
std::move(x); // has a name (we're moving from "x"), so it's a glvalue
// can be moved from, so it's an xvalue not an lvalue
foo(); // has no name, so is a prvalue, not a glvalue
X{}; // temporary has no name, so is a prvalue, not a glvalue
X{}.n; // HAS a name, so is a glvalue. can be moved from, so it's an xvalue
rvalue
एक अभिव्यक्ति की अभिव्यक्ति कोई भी अभिव्यक्ति है, जिसे इससे अलग किया जा सकता है, भले ही इसकी पहचान हो।
अधिक सटीक रूप से, rvalue अभिव्यक्तियों को एक फ़ंक्शन के तर्क के रूप में उपयोग किया जा सकता है जो T &&
(जहां T
expr
का प्रकार है) का पैरामीटर लेता है। इस तरह के फ़ंक्शन मापदंडों के तर्क के रूप में केवल भाव अभिव्यक्तियाँ दी जा सकती हैं; यदि एक गैर-रवैल्यू अभिव्यक्ति का उपयोग किया जाता है, तो अधिभार रिज़ॉल्यूशन किसी भी फ़ंक्शन को चुन लेगा जो कि रवैल्यू रेफरेंस पैरामीटर का उपयोग नहीं करता है। और अगर कोई भी मौजूद नहीं है, तो आपको एक त्रुटि मिलती है।
Rvalue अभिव्यक्तियों की श्रेणी में सभी xvalue और prvalue अभिव्यक्तियाँ शामिल हैं, और केवल वे अभिव्यक्तियाँ हैं।
मानक लाइब्रेरी फ़ंक्शन std::move
मौजूद है जो स्पष्ट रूप से एक गैर- rvalue अभिव्यक्ति को एक rvalue में बदलने के लिए मौजूद है। अधिक विशेष रूप से, यह अभिव्यक्ति को एक xvalue में बदल देता है, भले ही यह पहले पहचान-कम प्रचलित अभिव्यक्ति थी, इसे std::move
पैरामीटर के रूप में पास करके, यह पहचान (फ़ंक्शन का पैरामीटर नाम) प्राप्त करता है और xvalue बन जाता है।
निम्नलिखित को धयान मे रखते हुए:
std::string str("init"); //1
std::string test1(str); //2
std::string test2(std::move(str)); //3
str = std::string("new value"); //4
std::string &&str_ref = std::move(str); //5
std::string test3(str_ref); //6
std::string
में एक कंस्ट्रक्टर होता है जो एक प्रकार का पैरामीटर लेता है std::string&&
, जिसे "मूव कंस्ट्रक्टर" कहा जाता है। हालांकि, अभिव्यक्ति के मूल्य वर्ग str
नहीं एक rvalue (विशेष रूप से यह एक lvalue हैं), तो यह है कि निर्माता अधिभार फोन नहीं कर सकते हैं। इसके बजाय, यह const std::string&
overload, copy constructor कहता है।
लाइन 3 चीजों को बदल देती है। std::move
का रिटर्न मान T&&
, जहाँ T
, पास किया गया पैरामीटर का आधार प्रकार है। इसलिए std::move(str)
रिटर्न std::string&&
। एक फ़ंक्शन कॉल जो वापसी का मान है, एक रेवल्यू रेफरेंस है, एक रिवेल्यू एक्सप्रेशन (विशेष रूप से एक एक्सवल्यू) है, इसलिए इसे std::string
का मूव कंस्ट्रक्टर कह सकते हैं। पंक्ति 3 के बाद, str
से ले जाया गया है (जो सामग्री अब अपरिभाषित है)।
पंक्ति 4 std::string
के असाइनमेंट ऑपरेटर के लिए एक अस्थायी पास करती है। इसमें एक अधिभार है जो एक std::string&&
लेता है। अभिव्यक्ति std::string("new value")
एक rvalue अभिव्यक्ति (विशेष रूप से एक प्रचलन) है, इसलिए इसे उस अधिभार को कहा जा सकता है। इस प्रकार, अस्थायी को विशेष सामग्री के साथ अपरिभाषित सामग्री की जगह, str
में ले जाया जाता है।
लाइन 5 एक नामित नाम का संदर्भ बनाता है जिसे str_ref
कहा जाता है जो str
को संदर्भित करता है। यह वह जगह है जहाँ मूल्य श्रेणियां भ्रमित होती हैं।
देखें, जबकि str_ref
std::string
के लिए एक str_ref
है , एक्सप्रेशन str_ref
का मान श्रेणी कोई str_ref
नहीं है । यह एक लवलीन अभिव्यक्ति है। हाँ सच। इस वजह से, एक की चाल निर्माता कॉल नहीं कर सकते std::string
अभिव्यक्ति के साथ str_ref
। पंक्ति 6 इसलिए प्रतियों की मूल्य str
में test3
।
इसे स्थानांतरित करने के लिए, हमें std::move
पुन std::move
करना होगा।