c++ - राजस्व, अंतराल, xvalues, glvalues, और prvalues क्या हैं?




expression c++-faq (8)

सी ++ 03 में, एक अभिव्यक्ति या तो एक रैवल्यू या एक लाभा है

सी ++ 11 में, एक अभिव्यक्ति एक हो सकती है:

  1. rvalue
  2. lvalue
  3. XValue
  4. glvalue
  5. prvalue

दो श्रेणियां पांच श्रेणियां बन गई हैं।

  • अभिव्यक्तियों की ये नई श्रेणियां क्या हैं?
  • ये नई श्रेणियां मौजूदा रावल्यू और लैवल्यू श्रेणियों से कैसे संबंधित हैं?
  • क्या सी ++ 0x में रैवल्यू और लैवल्यू श्रेणियां समान हैं जैसे वे सी ++ 03 में हैं?
  • इन नई श्रेणियों की आवश्यकता क्यों है? क्या WG21 देवता सिर्फ हमें केवल प्राणियों को भ्रमित करने की कोशिश कर रहे हैं?

अभिव्यक्तियों की ये नई श्रेणियां क्या हैं?

एफसीडी (एन 30 9 2) में एक उत्कृष्ट विवरण है:

- एक अंतराल (तथाकथित, ऐतिहासिक रूप से, क्योंकि एक असाइनमेंट अभिव्यक्ति के बायीं तरफ अंतराल दिखाई दे सकता है) एक समारोह या वस्तु निर्दिष्ट करता है। [उदाहरण: यदि ई सूचक प्रकार की अभिव्यक्ति है, तो * ई एक लवली अभिव्यक्ति है जो ऑब्जेक्ट या फ़ंक्शन को संदर्भित करती है जिसमें ई पॉइंट्स हैं। एक और उदाहरण के रूप में, एक फ़ंक्शन को कॉल करने का नतीजा जिसका रिटर्न टाइप एक लवल्यू संदर्भ है, एक लवल्यू है। उदाहरण के लिए]

- एक xvalue (एक "eXpiring" मान भी एक वस्तु को संदर्भित करता है, आमतौर पर अपने जीवनकाल के अंत के पास (ताकि इसके संसाधनों को स्थानांतरित किया जा सके, उदाहरण के लिए)। एक xvalue कुछ प्रकार के अभिव्यक्तियों का परिणाम है जिसमें रावल संदर्भ (8.3.2) शामिल हैं। [उदाहरण: फ़ंक्शन को कॉल करने का नतीजा जिसका रिटर्न टाइप एक रावल्यू संदर्भ है, एक xvalue है। उदाहरण के लिए]

- एक glvalue ("सामान्यीकृत" lvalue) एक lvalue या एक xvalue है।

- एक रैल्यू (जिसे ऐतिहासिक रूप से कहा जाता है, क्योंकि एक असाइनमेंट एक्सप्रेशन के दाईं ओर रावल दिखाई दे सकते हैं) एक xvalue, एक अस्थायी वस्तु (12.2) या उसके उपरोक्त है, या एक वस्तु जो किसी ऑब्जेक्ट से जुड़ी नहीं है।

- एक प्रबुद्ध ("शुद्ध" रावल्यू) एक रैल्यू है जो एक xvalue नहीं है। [उदाहरण: फ़ंक्शन को कॉल करने का नतीजा जिसका रिटर्न टाइप संदर्भ नहीं है, एक प्रकोप है। 12, 7.3e5, या सत्य जैसे शाब्दिक का मूल्य भी एक प्रबुद्ध है। उदाहरण के लिए]

प्रत्येक अभिव्यक्ति इस वर्गीकरण में मूलभूत वर्गीकरणों में से एक है: अंतराल, xvalue, या prvalue। अभिव्यक्ति की इस संपत्ति को इसकी मान श्रेणी कहा जाता है। [नोट: क्लॉज 5 में प्रत्येक अंतर्निर्मित ऑपरेटर की चर्चा से उत्पन्न होने वाले मूल्य की श्रेणी और ऑपरेटरों की मूल्य श्रेणियां इंगित करती हैं। उदाहरण के लिए, अंतर्निहित असाइनमेंट ऑपरेटर उम्मीद करते हैं कि बाएं ऑपरेंड एक लवल्यू है और सही ऑपरेंड एक प्रबल है और परिणामस्वरूप एक लाभा उत्पन्न करता है। उपयोगकर्ता द्वारा परिभाषित ऑपरेटर कार्य होते हैं, और वे मूल्यों की श्रेणियों की अपेक्षा करते हैं और उपज उनके पैरामीटर और रिटर्न प्रकारों द्वारा निर्धारित की जाती है। नोट नोट करें

मेरा सुझाव है कि आप पूरे खंड 3.10 लाभाओं और राजस्व को पढ़ते हैं

ये नई श्रेणियां मौजूदा रावल्यू और लैवल्यू श्रेणियों से कैसे संबंधित हैं?

फिर:

क्या सी ++ 0x में रैवल्यू और लैवल्यू श्रेणियां समान हैं जैसे वे सी ++ 03 में हैं?

अंतराल के अर्थशास्त्र ने विशेष रूप से चाल semantics के परिचय के साथ विकसित किया है।

इन नई श्रेणियों की आवश्यकता क्यों है?

ताकि निर्माण / असाइनमेंट को स्थानांतरित किया जा सके और समर्थित किया जा सके।


इन नई श्रेणियों की आवश्यकता क्यों है? क्या डब्लूजी 21 देवता सिर्फ हमें केवल प्राणियों को भ्रमित करने की कोशिश कर रहे हैं?

मुझे नहीं लगता कि अन्य उत्तरों (अच्छे हैं हालांकि उनमें से कई हैं) वास्तव में इस विशेष प्रश्न का उत्तर कैप्चर करते हैं। हां, ये श्रेणियां और इस तरह के अस्तित्व को स्थानांतरित करने की अनुमति देने के लिए मौजूद हैं, लेकिन जटिलता एक कारण के लिए मौजूद है। यह C ++ 11 में चलती सामग्री का एक अनियंत्रित नियम है:

आप केवल तभी स्थानांतरित होंगे जब ऐसा करने के लिए निर्विवाद रूप से सुरक्षित हो।

यही कारण है कि ये श्रेणियां मौजूद हैं: उन मूल्यों के बारे में बात करने में सक्षम होने के लिए जहां से उन्हें स्थानांतरित करना सुरक्षित है, और उन मूल्यों के बारे में बात करने के लिए जहां यह नहीं है।

आर-मूल्य संदर्भों के शुरुआती संस्करण में, आंदोलन आसानी से हुआ। बहुत आसानी से आसानी से पर्याप्त है कि जब उपयोगकर्ता का वास्तव में मतलब नहीं था तो निश्चित रूप से चलती चीजों के लिए बहुत सारी संभावनाएं थीं।

यहां ऐसी परिस्थितियां हैं जिनके तहत कुछ स्थानांतरित करना सुरक्षित है:

  1. जब यह एक अस्थायी या subobject है। (Prvalue)
  2. जब उपयोगकर्ता ने स्पष्ट रूप से इसे स्थानांतरित करने के लिए कहा है

अगर तुम यह करते हो:

SomeType &&Func() { ... }

SomeType &&val = Func();
SomeType otherVal{val};

यह क्या करता है Spec के पुराने संस्करणों में, 5 मान आने से पहले, यह एक कदम को उकसाएगा। बिलकुल यह करता है। आपने कन्स्ट्रक्टर के लिए एक रावल्यू संदर्भ पारित किया है, और इस प्रकार यह उस कन्स्ट्रक्टर से जुड़ा हुआ है जो एक रावल्यू संदर्भ लेता है। ज़ाहिर सी बात है।

इसके साथ सिर्फ एक समस्या है; आपने इसे स्थानांतरित करने के लिए नहीं कहा था। ओह, आप कह सकते हैं कि && एक सुराग होना चाहिए था, लेकिन यह इस तथ्य को नहीं बदलेगा कि उसने नियम तोड़ दिया था। val अस्थायी नहीं है क्योंकि अस्थायी के पास नाम नहीं हैं। आपने अस्थायी जीवनकाल बढ़ाया हो सकता है, लेकिन इसका मतलब है कि यह अस्थायी नहीं है; यह किसी भी अन्य ढेर चर की तरह है।

यदि यह अस्थायी नहीं है, और आपने इसे स्थानांतरित करने के लिए नहीं कहा है, तो आगे बढ़ना गलत है।

स्पष्ट समाधान val एक लाभा बनाने के लिए है। इसका मतलब है कि आप इससे आगे नहीं बढ़ सकते हैं। अच्छी बात है; इसका नाम है, इसलिए यह एक लाभा है।

एक बार ऐसा करने के बाद, आप अब यह नहीं कह सकते कि SomeType&& अर्थ हमेशा एक ही चीज़ है। अब आपने नामित रावल संदर्भ और अज्ञात रावल संदर्भों के बीच एक अंतर बना दिया है। खैर, नामित रावल संदर्भ संदर्भ हैं; वह ऊपर हमारा समाधान था। तो हम अज्ञात रैल्यू संदर्भ (उपरोक्त Func से वापसी मूल्य) क्या कहते हैं?

यह एक लालसा नहीं है, क्योंकि आप एक लाभा से नहीं जा सकते हैं। और हमें एक && ; लौटकर स्थानांतरित करने में सक्षम होना चाहिए; आप कुछ और स्थानांतरित करने के लिए स्पष्ट रूप से कह सकते हैं? यही कारण है कि std::move वापसी, सब के बाद। यह एक रैल्यू (पुरानी शैली) नहीं है, क्योंकि यह समीकरण के बाईं तरफ हो सकता है (चीजें वास्तव में थोड़ा अधिक जटिल हैं, इस प्रश्न और नीचे दी गई टिप्पणियां देखें)। यह न तो एक लालसा और न ही एक राजस्व है; यह एक नई तरह की बात है।

हमारे पास एक मूल्य है जिसे आप एक लाभार्थी के रूप में देख सकते हैं, सिवाय इसके कि यह स्पष्ट रूप से चलने योग्य है । हम इसे एक xvalue कहते हैं

ध्यान दें कि xvalues ​​वे हैं जो हमें मूल्यों की अन्य दो श्रेणियां प्राप्त करते हैं:

  • एक प्रक्षेपण वास्तव में पिछले प्रकार के रावल्यू के लिए सिर्फ नया नाम है, यानी वे ऐसे रावल हैं जो xvalues नहीं हैं

  • Glvalues ​​एक समूह में xvalues ​​और lvalues ​​का संघ है , क्योंकि वे बहुत सारी संपत्तियों को साझा करते हैं।

तो वास्तव में, यह सब xvalues ​​के लिए नीचे आता है और आंदोलन को बिल्कुल और केवल कुछ स्थानों पर सीमित करने की आवश्यकता है। उन स्थानों को रैवल्यू श्रेणी द्वारा परिभाषित किया गया है; मूल्य अंतर्निहित चाल हैं, और xvalues ​​स्पष्ट चाल हैं ( std::move एक xvalue देता है)।


परिचय

आईएसओसी ++ 11 (आधिकारिक तौर पर आईएसओ / आईईसी 14882: 2011) सी ++ प्रोग्रामिंग भाषा के मानक का सबसे हालिया संस्करण है। इसमें कुछ नई विशेषताएं और अवधारणाएं हैं, उदाहरण के लिए:

  • रावल संदर्भ
  • xvalue, glvalue, prvalue अभिव्यक्ति मूल्य श्रेणियों
  • semantics ले जाएँ

अगर हम नई अभिव्यक्ति मूल्य श्रेणियों की अवधारणाओं को समझना चाहते हैं तो हमें इस बात से अवगत होना चाहिए कि रैवल्यू और लैवल्यू संदर्भ हैं। यह जानना बेहतर है कि राजस्व गैर-कॉन्स रावल संदर्भों को पारित किया जा सकता है।

int& r_i=7; // compile error
int&& rr_i=7; // OK

हम मूल्य श्रेणियों की अवधारणाओं के बारे में कुछ अंतर्ज्ञान प्राप्त कर सकते हैं यदि हम कामकाजी मसौदे N3337 (प्रकाशित आईएसओसी ++ 11 मानक के लिए सबसे समान मसौदा) से लाभार्थियों और रावलों के उपधारा का उद्धरण देते हैं।

3.10 अंतराल और राजस्व [मूल। Lval]

1 अभिव्यक्तियों को चित्रा 1 में वर्गीकरण के अनुसार वर्गीकृत किया गया है।

  • एक अंतराल (तथाकथित, ऐतिहासिक रूप से, क्योंकि एक असाइनमेंट अभिव्यक्ति के बायीं तरफ अंतराल दिखाई दे सकता है) एक समारोह या वस्तु निर्दिष्ट करता है। [उदाहरण: यदि ई सूचक प्रकार की अभिव्यक्ति है, तो * ई एक लवली अभिव्यक्ति है जो ऑब्जेक्ट या फ़ंक्शन को संदर्भित करती है जिसमें ई पॉइंट्स हैं। एक और उदाहरण के रूप में, एक फ़ंक्शन को कॉल करने का नतीजा जिसका रिटर्न टाइप एक लवल्यू संदर्भ है, एक लवल्यू है। उदाहरण के लिए]
  • एक xvalue (एक "expiring" मान भी एक वस्तु को संदर्भित करता है, आमतौर पर अपने जीवनकाल के अंत के पास (ताकि इसके संसाधनों को स्थानांतरित किया जा सके, उदाहरण के लिए)। एक xvalue कुछ प्रकार के अभिव्यक्तियों का परिणाम है जिसमें रावल संदर्भ (8.3.2) शामिल हैं। [उदाहरण: फ़ंक्शन को कॉल करने का नतीजा जिसका रिटर्न टाइप एक रावल्यू संदर्भ है, एक xvalue है। उदाहरण के लिए]
  • एक glvalue ("सामान्यीकृत" lvalue) एक lvalue या एक xvalue है।
  • एक रैल्यू (जिसे ऐतिहासिक रूप से कहा जाता है, क्योंकि एक असाइनमेंट अभिव्यक्ति के दाईं ओर रावल दिखाई दे सकते हैं) एक xvalue है, एक
    अस्थायी वस्तु (12.2) या इसके उपनिवेश, या एक मान जो नहीं है
    एक वस्तु से जुड़े।
  • एक प्रबुद्ध ("शुद्ध" रावल्यू) एक रैल्यू है जो एक xvalue नहीं है। [उदाहरण: फ़ंक्शन को कॉल करने का नतीजा जिसका रिटर्न टाइप नहीं है
    संदर्भ एक प्रवण है। एक शाब्दिक का मूल्य जैसे कि 12, 7.3e5, या
    सच भी एक प्रबुद्ध है। उदाहरण के लिए]

प्रत्येक अभिव्यक्ति इस वर्गीकरण में मूलभूत वर्गीकरणों में से एक है: अंतराल, xvalue, या prvalue। अभिव्यक्ति की इस संपत्ति को इसकी मान श्रेणी कहा जाता है।

लेकिन मुझे पूरा यकीन नहीं है कि यह उपखंड अवधारणाओं को स्पष्ट रूप से समझने के लिए पर्याप्त है, क्योंकि "आमतौर पर" वास्तव में सामान्य नहीं है, "अपने जीवनकाल के अंत में" वास्तव में ठोस नहीं है, "रावल संदर्भों" शामिल है वास्तव में स्पष्ट नहीं है, और "उदाहरण: फ़ंक्शन को कॉल करने का नतीजा जिसका रिटर्न प्रकार एक रावल्यू संदर्भ है, एक xvalue है।" एक सांप की तरह लगता है इसकी पूंछ काट रहा है।

प्राथमिक मूल्य श्रेणियां

प्रत्येक अभिव्यक्ति बिल्कुल एक प्राथमिक मूल्य श्रेणी से संबंधित है। ये मूल्य श्रेणियां lvalue, xvalue और prvalue श्रेणियां हैं।

lvalues

अभिव्यक्ति ई lvalue श्रेणी से संबंधित है और केवल अगर ई किसी ऐसी इकाई को संदर्भित करता है जिसे पहले पहचान (पता, नाम या उपनाम) है जो इसे ई के बाहर सुलभ बनाता है।

#include <iostream>

int i=7;

const int& f(){
    return i;
}

int main()
{
    std::cout<<&"www"<<std::endl; // This address ...
    std::cout<<&"www"<<std::endl; // ... and this address are the same.
    "www"; // The expression "www" in this row is an lvalue expression, because it refers to the same entity ...
    "www"; // ... as the entity the expression "www" in this row refers to.

    i; // The expression i in this row is an lvalue expression, because it refers to the same entity ...
    i; // ... as the entity the expression i in this row refers to.

    int* p_i=new int(7);
    *p_i; // The expression *p_i in this row is an lvalue expression, because it refers to the same entity ...
    *p_i; // ... as the entity the expression *p_i in this row refers to.

    const int& r_I=7;
    r_I; // The expression r_I in this row is an lvalue expression, because it refers to the same entity ...
    r_I; // ... as the entity the expression r_I in this row refers to.

    f(); // The expression f() in this row is an lvalue expression, because it refers to the same entity ...
    i; // ... as the entity the expression f() in this row refers to.

    return 0;
}

XValues

अभिव्यक्ति ई xvalue श्रेणी से संबंधित है और केवल अगर यह है

- एक फ़ंक्शन को कॉल करने का नतीजा, चाहे वह स्पष्ट रूप से या स्पष्ट रूप से हो, जिसका रिटर्न प्रकार वापस आने वाले ऑब्जेक्ट के प्रकार का एक रावल्यू संदर्भ है, या

int&& f(){
    return 3;
}

int main()
{
    f(); // The expression f() belongs to the xvalue category, because f() return type is an rvalue reference to object type.

    return 0;
}

- वस्तु प्रकार के लिए एक rvalue संदर्भ के लिए एक कलाकार, या

int main()
{
    static_cast<int&&>(7); // The expression static_cast<int&&>(7) belongs to the xvalue category, because it is a cast to an rvalue reference to object type.
    std::move(7); // std::move(7) is equivalent to static_cast<int&&>(7).

    return 0;
}

- एक वर्ग सदस्य पहुंच अभिव्यक्ति गैर-संदर्भ प्रकार के गैर-स्थैतिक डेटा सदस्य को निर्दिष्ट करती है जिसमें ऑब्जेक्ट अभिव्यक्ति एक xvalue है, या

struct As
{
    int i;
};

As&& f(){
    return As();
}

int main()
{
    f().i; // The expression f().i belongs to the xvalue category, because As::i is a non-static data member of non-reference type, and the subexpression f() belongs to the xvlaue category.

    return 0;
}

- एक पॉइंटर-टू-सदस्य अभिव्यक्ति जिसमें पहला ऑपरेंड एक xvalue है और दूसरा ऑपरेंड डेटा सदस्य के लिए एक सूचक है।

ध्यान दें कि उपरोक्त नियमों का प्रभाव यह है कि ऑब्जेक्ट्स के लिए रावल संदर्भों को नामित किया जाता है, जिन्हें वस्तुओं के लिए लंबित माना जाता है और अज्ञात रावल संदर्भों को xvalues ​​के रूप में माना जाता है; कार्यों के लिए रैल्यू संदर्भों को नाम दिया गया है या नहीं, के रूप में माना जाता है।

#include <functional>

struct As
{
    int i;
};

As&& f(){
    return As();
}

int main()
{
    f(); // The expression f() belongs to the xvalue category, because it refers to an unnamed rvalue reference to object.
    As&& rr_a=As();
    rr_a; // The expression rr_a belongs to the lvalue category, because it refers to a named rvalue reference to object.
    std::ref(f); // The expression std::ref(f) belongs to the lvalue category, because it refers to an rvalue reference to function.

    return 0;
}

prvalues

अभिव्यक्ति ई प्रवाल श्रेणी से संबंधित है यदि केवल और यदि ई न तो अंतराल से और न ही xvalue श्रेणी से संबंधित है।

struct As
{
    void f(){
        this; // The expression this is a prvalue expression. Note, that the expression this is not a variable.
    }
};

As f(){
    return As();
}

int main()
{
    f(); // The expression f() belongs to the prvalue category, because it belongs neither to the lvalue nor to the xvalue category.

    return 0;
}

मिश्रित मूल्य श्रेणियां

दो और महत्वपूर्ण मिश्रित मूल्य श्रेणियां हैं। ये मूल्य श्रेणियां रैवल्यू और ग्लवल्यू श्रेणियां हैं।

rvalues

अभिव्यक्ति ई रावल श्रेणी से संबंधित है यदि केवल और यदि ई xvalue श्रेणी से संबंधित है, या प्रवाल श्रेणी में है।

ध्यान दें कि इस परिभाषा का अर्थ है कि अभिव्यक्ति ई rvalue श्रेणी से संबंधित है और केवल अगर ई किसी ऐसी इकाई को संदर्भित करता है जिसकी कोई पहचान नहीं है जो इसे ई YET के बाहर सुलभ बनाता है।

glvalues

अभिव्यक्ति ई glvalue श्रेणी से संबंधित है और केवल अगर ई lvalue श्रेणी, या xvalue श्रेणी से संबंधित है।

एक व्यावहारिक नियम

स्कॉट मेयर ने अंगूठे से राजस्व को अलग करने के लिए अंगूठे का एक बहुत ही उपयोगी नियम published है।

  • यदि आप अभिव्यक्ति का पता ले सकते हैं, तो अभिव्यक्ति एक लालसा है।
  • यदि अभिव्यक्ति का प्रकार एक लवल्यू संदर्भ है (उदाहरण के लिए, टी एंड या कॉन्स्ट टी एंड इत्यादि), तो अभिव्यक्ति एक अंतराल है।
  • अन्यथा, अभिव्यक्ति एक रैल्यू है। संकल्पनात्मक रूप से (और आम तौर पर भी वास्तव में), राजस्व अस्थायी वस्तुओं से मेल खाता है, जैसे कार्यों से लौटाया गया या निहित प्रकार रूपांतरणों के माध्यम से बनाया गया। अधिकांश शाब्दिक मूल्य (उदाहरण के लिए, 10 और 5.3) भी रावल हैं।

आईएमएचओ, इसके अर्थ के बारे में सबसे अच्छी व्याख्या हमें stroustrup.com/terminology.pdf + देनील सैंडोर और Mohan उदाहरणों को ध्यान में रखती है :

Stroustrup:

अब मैं गंभीरता से चिंतित था। स्पष्ट रूप से हम एक बाधा या गड़बड़ या दोनों के लिए नेतृत्व कर रहे थे। मैंने दोपहर का भोजन करने के लिए एक विश्लेषण किया, यह देखने के लिए कि कौन से गुण (मूल्यों) स्वतंत्र थे। केवल दो स्वतंत्र गुण थे:

  • has identity - यानी पता, एक सूचक, उपयोगकर्ता निर्धारित कर सकता है कि दो प्रतियां समान हैं, आदि।
  • can be moved from - यानी हमें कुछ अनिश्चित, लेकिन वैध स्थिति में "प्रतिलिपि" के स्रोत पर जाने की अनुमति है

इससे मुझे निष्कर्ष निकाला गया कि वास्तव में तीन प्रकार के मूल्य हैं (ऋणात्मक संकेत देने के लिए पूंजी पत्र का उपयोग करने के रेगेक्स नोटिकल चाल का उपयोग करके - मैं जल्दबाजी में था):

  • iM : पहचान है और इसे स्थानांतरित नहीं किया जा सकता है
  • im : पहचान है और इसे स्थानांतरित किया जा सकता है (उदाहरण के लिए एक रैवल्यू संदर्भ में एक लाभा कास्टिंग का परिणाम)
  • Im : पहचान नहीं है और चौथी संभावना से स्थानांतरित किया जा सकता है ( IM : पहचान नहीं है और स्थानांतरित नहीं किया जा सकता है) किसी भी अन्य भाषा में C++ (या, मुझे लगता है) में उपयोगी नहीं है।

मूल्यों के इन तीन मौलिक वर्गीकरणों के अलावा, हमारे पास दो स्पष्ट सामान्यीकरण हैं जो दो स्वतंत्र गुणों से मेल खाते हैं:

  • i : पहचान है
  • m : से स्थानांतरित किया जा सकता है

इसने मुझे इस आरेख को बोर्ड पर डालने का नेतृत्व किया:

नामकरण

मैंने देखा कि हमारे पास नाम देने के लिए केवल सीमित स्वतंत्रता थी: बाएं दो बिंदु (लेबल iM और i ) वे हैं जो कम या कम औपचारिकता वाले लोगों को lvalues कहते हैं और दाईं ओर दो बिंदु (लेबल m और Im ) लोग हैं अधिक या कम औपचारिकता के साथ rvalues कहा जाता है। यह हमारे नामकरण में परिलक्षित होना चाहिए। यही है, W के बाएं "पैर" में lvalue से संबंधित नाम होना चाहिए और W के दाहिने "पैर" में rvalue. से संबंधित नाम होना चाहिए rvalue. मुझे लगता है कि यह पूरी चर्चा / समस्या रावल संदर्भों की शुरूआत से उत्पन्न होती है और अर्थशास्त्र को स्थानांतरित करती है। ये धारणाएं केवल स्ट्रैची की दुनिया में मौजूद नहीं हैं, जिसमें केवल rvalues और lvalues । किसी ने देखा कि विचार है कि

  • प्रत्येक value या तो एक lvalue या एक rvalue
  • एक lvalue एक lvalue नहीं है और एक rvalue एक rvalue नहीं है

हमारी चेतना, बहुत उपयोगी गुणों में गहराई से एम्बेडेड हैं, और इस डिचोटोमी के निशान सभी ड्राफ्ट मानक में पाए जा सकते हैं। हम सभी सहमत हैं कि हमें उन गुणों को संरक्षित करना चाहिए (और उन्हें सटीक बनाना)। इससे आगे हमारे नामकरण विकल्पों को बाधित किया गया। मैंने देखा कि मानक लाइब्रेरी शब्द का मतलब m (सामान्यीकरण) के लिए rvalue का उपयोग करता है, ताकि मानक पुस्तकालय की अपेक्षा और पाठ को संरक्षित किया जा सके, W के दाएं हाथ के नीचे बिंदु को rvalue. नाम दिया जाना चाहिए rvalue.

इससे नामकरण की एक केंद्रित चर्चा हुई। सबसे पहले, हमें lvalue. पर फैसला करने की आवश्यकता थी lvalue. क्या lvalue मतलब iM या सामान्यीकरण चाहिए? डौग ग्रेगोर के नेतृत्व में, हमने मूल भाषा शब्द में जगहों को सूचीबद्ध किया जहां शब्द एक दूसरे के अर्थ के लिए योग्य था। एक सूची बनाई गई थी और ज्यादातर मामलों में और सबसे मुश्किल / भंगुर पाठ में वर्तमान में iM मतलब है। यह लालू का शास्त्रीय अर्थ है क्योंकि "पुराने दिनों में" कुछ भी नहीं चले गए; move C++0x में एक उपन्यास धारणा है। इसके अलावा, W lvalue के अपूर्ण बिंदु नामकरण हमें संपत्ति देता है कि हर मूल्य एक lvalue या एक rvalue , लेकिन दोनों नहीं।

तो, W का शीर्ष बायां बिंदु lvalue और नीचे दाएं बिंदु rvalue. यह नीचे बाएं और शीर्ष दाएं बिंदु क्या बनाता है? निचला बायां बिंदु क्लासिकल लैवल्यू का एक सामान्यीकरण है, जो चलने की इजाजत देता है। तो यह एक generalized lvalue. हमने इसे glvalue. नाम दिया glvalue. आप संक्षिप्त नाम के बारे में चिंतित हो सकते हैं, लेकिन (मुझे लगता है) तर्क के साथ नहीं। हमने माना कि गंभीर उपयोग में generalized lvalue किसी भी तरह से संक्षेप में संक्षेप में किया जाएगा, इसलिए हमने इसे तुरंत बेहतर किया था (या जोखिम भ्रम)। डब्ल्यू का शीर्ष दायां बिंदु नीचे दाएं से कम सामान्य है (अब, जैसा कि कभी भी, rvalue कहा जाता है)। वह बिंदु किसी ऑब्जेक्ट की मूल शुद्ध धारणा का प्रतिनिधित्व करता है जिसे आप स्थानांतरित कर सकते हैं क्योंकि इसे फिर से संदर्भित नहीं किया जा सकता है (विनाशक को छोड़कर)। मुझे generalized lvalue prvalue विपरीत वाक्यांश specialized rvalue पसंद आया लेकिन pure rvalue prvalue संक्षिप्त रूप से prvalue गया (और शायद सही है)। तो, डब्ल्यू का बायां पैर glvalue और glvalue और दाहिना पैर prvalue और rvalue. संयोग से, हर मूल्य या तो एक glvalue या एक prvalue है, लेकिन दोनों नहीं।

यह W के शीर्ष मध्य को छोड़ देता है: im ; यही वह मूल्य है जिसमें पहचान है और इसे स्थानांतरित किया जा सकता है। हमारे पास वास्तव में कुछ भी नहीं है जो हमें उन गूढ़ जानवरों के लिए एक अच्छे नाम के लिए मार्गदर्शन करता है। वे (ड्राफ्ट) मानक पाठ के साथ काम करने वाले लोगों के लिए महत्वपूर्ण हैं, लेकिन घर का नाम बनने की संभावना नहीं है। हमें मार्गदर्शन करने के लिए नामकरण पर हमें कोई वास्तविक बाधा नहीं मिली, इसलिए हमने केंद्र, अज्ञात, अजीब, केवल xpert, या यहां तक ​​कि एक्स-रेटेड के लिए 'x' चुना।


मैं आपके अंतिम प्रश्न से शुरू करूंगा:

इन नई श्रेणियों की आवश्यकता क्यों है?

सी ++ मानक में कई नियम होते हैं जो अभिव्यक्ति की मान श्रेणी से निपटते हैं। कुछ नियम lvalue और rvalue के बीच एक अंतर बनाते हैं। उदाहरण के लिए, जब अधिभार संकल्प की बात आती है। अन्य नियम glvalue और prvalue के बीच एक अंतर बनाते हैं। उदाहरण के लिए, आप एक अपूर्ण या अमूर्त प्रकार के साथ एक glvalue हो सकता है लेकिन अपूर्ण या अमूर्त प्रकार के साथ कोई प्रक्षेपण नहीं है। इससे पहले कि हम इस शब्दावली को नियमों के बारे में बताते हैं, जिन्हें वास्तव में अंतराल / रावल्यू के संदर्भ में ग्लूवल / प्रवाल के बीच अंतर करने की आवश्यकता होती है और वे या तो अनजाने में गलत थे या नियम के लिए अपवाद और अपवादों के बहुत सारे थे "... जब तक कि रावल्यू अज्ञात नहीं है रावल संदर्भ ... "। तो, ऐसा लगता है कि केवल glvalues ​​की अवधारणाओं को देना और उनके नाम का प्रचार करना एक अच्छा विचार है।

अभिव्यक्तियों की ये नई श्रेणियां क्या हैं? ये नई श्रेणियां मौजूदा रावल्यू और लैवल्यू श्रेणियों से कैसे संबंधित हैं?

हमारे पास अभी भी शब्द Lvalue और Rvalue है जो C ++ 98 के साथ संगत हैं। हमने रावलों को दो उपसमूहों, xvalues ​​और prvalues ​​में विभाजित किया है, और हम अंतराल और xvalues ​​को glvalues ​​के रूप में संदर्भित करते हैं। अज्ञात रावल संदर्भों के लिए Xvalues ​​एक नई प्रकार की मान श्रेणी है। प्रत्येक अभिव्यक्ति इन तीनों में से एक है: lvalue, xvalue, prvalue। एक वेन आरेख इस तरह दिखेगा:

    ______ ______
   /      X      \
  /      / \      \
 |   l  | x |  pr  |
  \      \ /      /
   \______X______/
       gl    r

कार्यों के साथ उदाहरण:

int   prvalue();
int&  lvalue();
int&& xvalue();

लेकिन यह भी मत भूलना कि नामित रावल संदर्भ संदर्भ हैं:

void foo(int&& t) {
  // t is initialized with an rvalue expression
  // but is actually an lvalue expression itself
}

मैंने लंबे समय तक इसके साथ संघर्ष किया है, जब तक कि मैं मूल्य श्रेणियों के cppreference.com स्पष्टीकरण में नहीं आया।

यह वास्तव में अपेक्षाकृत सरल है, लेकिन मुझे लगता है कि इसे अक्सर इस तरह से समझाया जाता है कि याद रखना मुश्किल है। यहां यह बहुत schematically समझाया गया है। मैं पृष्ठ के कुछ हिस्सों को उद्धृत करूंगा:

प्राथमिक श्रेणियां

प्राथमिक मूल्य श्रेणियां अभिव्यक्तियों के दो गुणों से मेल खाती हैं:

  • has identity : it's possible to determine whether the expression refers to the same entity as another expression, such as by comparing addresses of the objects or the functions they identify (obtained directly or indirectly);

  • can be moved from : move constructor, move assignment operator, or another function overload that implements move semantics can bind to the expression.

Expressions that:

  • have identity and cannot be moved from are called lvalue expressions ;
  • have identity and can be moved from are called xvalue expressions ;
  • do not have identity and can be moved from are called prvalue expressions ;
  • do not have identity and cannot be moved from are not used.

lvalue

An lvalue ("left value") expression is an expression that has identity and cannot be moved from .

rvalue (until C++11), prvalue (since C++11)

A prvalue ("pure rvalue") expression is an expression that does not have identity and can be moved from .

xvalue

An xvalue ("expiring value") expression is an expression that has identity and can be moved from .

glvalue

A glvalue ("generalized lvalue") expression is an expression that is either an lvalue or an xvalue. It has identity . It may or may not be moved from.

rvalue (since C++11)

An rvalue ("right value") expression is an expression that is either a prvalue or an xvalue. It can be moved from . It may or may not have identity.


In C++, variables are a type of l-value (pronounced ell-value). An l-value is a value that has a persistent address (in memory). Since all variables have addresses, all variables are l-values. The name l-value came about because l-values are the only values that can be on the left side of an assignment statement. When we do an assignment, the left-hand side of the assignment operator must be an l-value. Consequently, a statement like 5 = 6; will cause a compile error, because 5 is not an l-value. The value of 5 has no memory, and thus nothing can be assigned to it. 5 means 5, and its value can not be reassigned. When an l-value has a value assigned to it, the current value at that memory address is overwritten.

The opposite of l-values are r-values (pronounced arr-values). An r-value refers to values that are not associated with a persistent memory address. Examples of r-values are single numbers (such as 5, which evaluates to 5) and expressions (such as 2 + x, which evaluates to the value of variable x plus 2). r-values are generally temporary in nature and are discarded at the end of the statement in which they occur.

Here is an example of some assignment statements, showing how the r-values evaluate:

int y;      // define y as an integer variable
y = 4;      // r-value 4 evaluates to 4, which is then assigned to l-value y
y = 2 + 5;  // r-value 2 + r-value 5 evaluates to r-value 7, which is then assigned to l-value y

int x;      // define x as an integer variable
x = y;      // l-value y evaluates to 7 (from before), which is then assigned to l-value x.
x = x;      // l-value x evaluates to 7, which is then assigned to l-value x (useless!)
x = x + 1;  // l-value x + r-value 1 evaluate to r-value 8, which is then assigned to l-value x.

Let's take a closer look at the last assignment statement above, since it causes the most confusion.

x = x+1

In this statement, the variable x is being used in two different contexts. On the left side of the assignment operator, “x” is being used as an l-value (variable with an address) in which to store a value. On the right side of the assignment operator, x is evaluated to produce a value (in this case, 7). When C++ evaluates the above statement, it evaluates as:

x = 7+1

Which makes it obvious that C++ will assign the value 8 back into variable x.

For the time being, you don't need to worry about l-values or r-values much, but we'll return to them later when we start discussing some more advanced topics.

The key takeaway here is that on the left side of the assignment, you must have something that represents a memory address (such as a variable). Everything on the right side of the assignment will be evaluated to produce a value.


One addendum to the excellent answers above, on a point that confused me even after I had read Stroustrup and thought I understood the rvalue/lvalue distinction. When you see

int&& a = 3 ,

it's very tempting to read the int&& as a type and conclude that a is an rvalue. It's not:

int&& a = 3;
int&& c = a; //error: cannot bind 'int' lvalue to 'int&&'
int& b = a; //compiles

a has a name and is ipso facto an lvalue. Don't think of the && as part of the type of a ; it's just something telling you what a is allowed to bind to.

This matters particularly for T&& type arguments in constructors. If you write

Foo::Foo(T&& _t) : t{_t} {}

you will copy _t into t . You need

Foo::Foo(T&& _t) : t{std::move(_t)} {} if you want to move. Would that my compiler warned me when I left out the move !





c++11