2012-12-23 14 views
11

संभव डुप्लिकेट:
What happens if I return literal instead of declared std::string?समझने C++ 11 rvalues, अर्थ विज्ञान के लिए कदम और प्रदर्शन

निम्नलिखित कोड

1| string getName() { 
2|  return "meme"; 
3| } 
4| 
5| string name = getName(); 

समारोह getName (पर विचार करें) एक रिटर्न अस्थायी वस्तु। सी ++ 03 में, मैं समझता हूं कि "स्ट्रिंग" की कॉपी कन्स्ट्रक्टर को बुलाया जाता है और अस्थायी वस्तु नष्ट हो जाती है। दरअसल ऐसा लगता है कि संकलक (जीसीसी 4.7 में कम से कम) ऑब्जेक्ट "नाम" नहीं बनाकर लाइन 5 को अनुकूलित करता है लेकिन इसे अस्थायी ऑब्जेक्ट के साथ बदलता है और अस्थायी ऑब्जेक्ट को नष्ट नहीं करता है (मैंने एक MyVector क्लास के साथ प्रयास किया है, std :: string नहीं)।

जैसा कि सी ++ 11 मानकों में परिभाषित किया गया है,
1. क्या getName() एक रैवल्यू लौटा रहा है?
2. उपरोक्त पंक्ति 5 में, स्ट्रिंग के किस कन्स्ट्रक्टर को कॉल (चाल या प्रतिलिपि) कहा जाता है? क्या मुझे जरूरी कदम कन्स्ट्रक्टर के लिए कॉल करने के लिए std :: move() को कॉल करना चाहिए?
3. चाल semantics के साथ, यह संकलक द्वारा प्रदान की गई "प्रतिलिपि प्रतिलिपि" अनुकूलन कम कुशल है?

+2

यह _copy elision _... –

+0

@ के-बॉलो मुझे प्रबुद्ध करने के लिए धन्यवाद होगा। –

+0

लाइन नंबर जोड़ना कमाल लग रहा है! कभी नहीं देखा कि पहले =) – qwertz

उत्तर

18
  1. कार्य वापसी नहीं rvalues ​​या lvalues ​​है। मूल्य श्रेणियां अभिव्यक्तियों पर लागू होती हैं। तो एक अभिव्यक्ति है कि कॉल एक फ़ंक्शन एक रैवल्यू या लैवल्यू हो सकता है। इस मामले में, अभिव्यक्ति getName() एक रैल्यू अभिव्यक्ति है क्योंकि फ़ंक्शन getName किसी ऑब्जेक्ट को मान द्वारा देता है। यह §5.2.2/10 से आता है:

    एक समारोह कॉल करता है, तो परिणाम प्रकार एक lvalue संदर्भ प्रकार या एक rvalue संदर्भ प्रकार कार्य करने के लिए, एक XValue है एक lvalue है अगर परिणाम प्रकार के लिए एक rvalue संदर्भ है ऑब्जेक्ट प्रकार, और अन्यथा का प्रसार।

    आपके फ़ंक्शंस परिणाम प्रकार एक लेल्यू या रावल्यू संदर्भ नहीं है, इसलिए फ़ंक्शन कॉल एक प्रावधान है। प्रबुद्ध अभिव्यक्तियां रैवल्यू अभिव्यक्तियों का एक उप-समूह हैं।

  2. चालक कन्स्ट्रक्टर का उपयोग किया जाएगा (जब तक यह elided नहीं है, जो यह हो सकता है)। ऐसा इसलिए है क्योंकि getName() एक रैल्यू है, इसलिए std::string का कन्स्ट्रक्टर जो एक रावल्यू संदर्भ लेता है, तर्क से बेहतर होगा। ध्यान दें कि भले ही चाल निर्माण को समाप्त किया गया हो, फिर भी चालक कन्स्ट्रक्टर को अभी भी सुलभ होना चाहिए। यही है, कोड को संकलित किया जाना चाहिए भले ही यह elided नहीं है।

  3. सामान्य रूप से, प्रतिलिपि या अनुकूलन का अनुकूलन किसी भी प्रतिलिपि या चलने से पूरी तरह से छुटकारा पा जाएगा। तो निश्चित रूप से यह वास्तव में एक कदम करने से तेज है। यदि एक कदम elided है, सचमुच कुछ भी नहीं होता है। उस कदम के लिए उत्सर्जित कोई कोड नहीं होगा। संकलक सीधे उस स्थान पर ऑब्जेक्ट का निर्माण करके प्राप्त करता है जिसकी प्रतिलिपि बनाई जाएगी या स्थानांतरित की जाएगी।

यह उल्लेख है कि यह भी समतुल्य रूप से अनुकूलित किया जा सकता है लायक है:

string getName() { 
    std::string str("meme"); 
    return str; 
} 

string name = getName(); 

इधर, दो कदम (शामिल जो सामान्यतः Named Return Value Optimization के रूप में जाना जाता है) elided कर दिया जाएगा। यहां पर विचार करने के लिए दो बिंदु हैं।

कॉपी/कदम आपरेशन के इस इलिजन, कहा जाता है प्रतिलिपि इलिजन, निम्नलिखित परिस्थितियों में अनुमति दी है (जो करने के लिए जोड़ा जा सकता है: सबसे पहले, return str; कॉपी/कदम इलिजन (§12.8/31) के मानदंडों के अनुरूप कई प्रतियां खत्म करने):

    एक वर्ग वापसी प्रकार के साथ एक समारोह में एक वापसी कथन, जब अभिव्यक्ति (एक गैर अस्थिर स्वत: ऑब्जेक्ट का नाम या साथ पकड़ने-खंड पैरामीटर एक समारोह के अलावा) में
  • फ़ंक्शन रिटर्न प्रकार के समान सीवी-अयोग्य प्रकार, कॉपी/मूव ऑपरेशन को स्वचालित ऑब्जेक्ट को सीधे int बनाकर छोड़ा जा सकता है ओ समारोह द्वारा दिया गया मान
  • ...

दूसरा है कि, हालांकि str एक lvalue है, यह अभी भी से, क्योंकि यह मानक द्वारा दिए गए एक विशेष मामला फिट बैठता ले जाया जाएगा है (§12.8/32):

जब एक प्रतिलिपि आपरेशन के इलिजन के लिए मानदंडों को पूरा कर रहे हैं या तथ्य यह है कि स्रोत ऑब्जेक्ट एक समारोह पैरामीटर, और वस्तु कॉपी किया जा करने के लिए एक lvalue द्वारा नामित किया जाता है के लिए सेव पूरी की जाएगी, अधिभार संकल्प प्रतिलिपि के लिए कन्स्ट्रक्टर का चयन करने के लिए पहले ऐसा किया जाता है जैसे ऑब्जेक्ट को नामित किया गया था b वाई एक रावल्यू।

संबंधित मुद्दे