2012-03-28 33 views
9

में रैल्यू संदर्भों का उपयोग करना मैं एक वेक्टर को भरने वाले फ़ंक्शन को कार्यान्वित करना चाहता हूं और फिर एक रावल्यू संदर्भ देता हूं। मैं की तरह थक कुछ:सी ++ 11

std::vector<int> &&fill_list() { 
    std::vector<int> res; 
    ... do something to fill res ... 
    return res; 
} 

int main(int argc, char **argv) { 
    std::vector<int> myvec = fill_list(); 
    return 0; 
} 

लेकिन वह काम नहीं करता, मैं निम्न त्रुटि:

error: invalid initialization of reference of type 'std::vector<int>&&' from expression of type 'std::vector<int>' 

तो, सब में, यह कैसे ऐसा करने का सही तरीका क्या है? मुझे नहीं लगता कि मुझे अभी तक रैवल्यू संदर्भ मिलते हैं।

+6

भले ही यह संकलित हो, फिर भी यह एक खतरनाक संदर्भ लौटाएगा। _Why_ क्या आप एक रावल्यू संदर्भ वापस करना चाहते हैं? आप मूल्य से वापस क्यों नहीं आते? – ildjarn

+0

जहां तक ​​मुझे पता है कि यह एक खतरनाक संदर्भ नहीं होगा, यह सी ++ 11 में चलती शब्दावली का पूरा बिंदु है, कम से कम मुझे दस्तावेज से मिलता है। – Sambatyon

+3

मुझे लगता है कि आपको रावल संदर्भों के बारे में उस बिंदु को गलत मिला है: यह है कि _value_ जिसे नष्ट किया जाएगा, उसे कॉपी करने की आवश्यकता के बजाय इसे स्थानांतरित किया जा सकता है।यदि आप सीधे एक रावल्यू संदर्भ वापस करते हैं, तो _is_ कोई मूल्य नहीं है क्योंकि इसे नष्ट कर दिया गया है _before_ आपको इसकी सामग्री को स्थानांतरित करने का मौका मिला है। – leftaroundabout

उत्तर

27

आप उलझन में प्रतीत होते हैं कि एक रेवल्यू संदर्भ क्या है और यह अर्थशास्त्र को स्थानांतरित करने से कैसे संबंधित है।

पहली बात यह है कि: &&का मतलब स्थानांतरित नहीं है। यह एक विशेष संदर्भ प्रकार से अधिक कुछ नहीं है। यह है अभी भी एक संदर्भ।यह एक मूल्य नहीं है; यह मान नहीं है; यह एक मूल्य के लिए संदर्भ है। जिसका अर्थ है कि इसमें संदर्भ प्रकार की सभी सीमाएं हैं। विशेष रूप से, यह उस मान को संदर्भित करना चाहिए जो अभी भी मौजूद है। तो एक लटकती आर-वैल्यू संदर्भ लौटना एक लापरवाही एल-वैल्यू संदर्भ लौटने से बेहतर नहीं है।

"मूविंग" एक ऑब्जेक्ट दावा किसी अन्य ऑब्जेक्ट की सामग्री के स्वामित्व का दावा करने की प्रक्रिया है। आर-मान संदर्भ स्थानांतरित करें अर्थशास्त्र को स्थानांतरित करें, लेकिन केवल && होने का अर्थ यह नहीं है कि कुछ भी स्थानांतरित हो गया है। आंदोलन केवल तब होता है जब एक चालक कन्स्ट्रक्टर (या असाइनमेंट ऑपरेटर ले जाएं) कहा जाता है; जब तक कि उन दो चीजों में से एक नहीं कहा जाता है, कोई आंदोलन नहीं हुआ है।

आप उपयोगकर्ता के लिए अपने कार्य से बाहर एक std::vector की सामग्री को स्थानांतरित करना चाहते हैं, तो आप बस ऐसा करते हैं:

std::vector<int> myvec = fill_list(); 

दो में से एक:

std::vector<int> fill_list() { 
    std::vector<int> res; 
    ... do something to fill res ... 
    return res; 
} 

fill_list() के इस प्रयोग को देखते हुए चीजें घटित होंगी या तो वापसी को समाप्त किया जाएगा, जिसका मतलब है कि कोई प्रतिलिपि या चलती है। res सीधे myvec में बनाया गया है। या res को वापसी मूल्य में स्थानांतरित किया जाएगा, जो तब myvec की चाल-प्रारंभिकता करेगा। तो फिर, कोई प्रतिलिपि नहीं।

, तो आप इस था:

std::vector<int> myvec; 
myvec = fill_list(); 

फिर, यह में चले गए होंगे। कोई प्रतिलिपि नहीं

सी ++ 11 जानता है कि चीजों को स्पष्ट रूप से स्थानांतरित करना सुरक्षित है। संदर्भ या कुछ के बजाय मूल्य से मूल्य लौटाना हमेशा स्थानांतरित करने के लिए एक सुरक्षित समय है। इसलिए, यह चलेगा।

+0

अफसोस की बात है, सी ++ 11 बहुत सख्त है जब यह वास्तव में स्थानीय चर को स्थानांतरित करने का प्रयास करता है। यह केवल संकलक को ऐसा करने की इजाजत देता है यदि कॉपी एलिशन के लिए शर्तें लागू होती हैं, लेकिन किसी भी कारण से एलिजन कॉपी नहीं किया जा सकता है। यह अत्यधिक सख्त है, लेकिन इस मानक में मदद नहीं की जा सकती है। – Xeo

-1

यदि आप अपने कार्य से && हटाते हैं तो इसे काम करना चाहिए, लेकिन यह एक संदर्भ नहीं होगा। fill_list() एक वेक्टर बनायेगा और इसे वापस कर देगा। वापसी के दौरान एक नया वेक्टर बनाया जाएगा। Fill_list() के अंदर बनाया गया पहला वेक्टर नए वेक्टर में कॉपी किया जाएगा और फिर नष्ट हो जाएगा। यह कॉपी कन्स्ट्रक्टर का काम है।

+1

यदि यह मूल्य से लौटाया जाता है, तो यह एक _move_ कन्स्ट्रक्टर, एक कॉपी कन्स्ट्रक्टर नहीं। – ildjarn

+0

असल में, यह किसी भी रचनाकारों का जरूरी उपयोग नहीं करेगा क्योंकि आधुनिक कंपाइलर वापसी मूल्यों के लिए प्रतिलिपि बना सकते हैं। – leftaroundabout

+0

उसे नहीं पता था। असल में यह समय है कि वे करते हैं! :-) –

0

rvalue संदर्भ की चर्चा आप पढ़ सकते हैं क्या Bjarne Stroustrup, सी ++ के लेखक, यहाँ उनके बारे में क्या कहना है के लिए: अपने विशिष्ट उदाहरण को संबोधित करते

http://www2.research.att.com/~bs/C++0xFAQ.html#rval

, संक्षिप्त उत्तर है की वजह से है कि नाम वापसी मूल्य अनुकूलन - जो एक वास्तविक मानक C++ कम्पाइलर सुविधा है भी पूर्व सी ++ 11 - अगर आप बस लौट-दर-मूल्य संकलक अप रेस टाई और होगा myvec कुशलता की तरह आप चाहते हैं:

std::vector<int> fill_list() { 
    std::vector<int> res; 
    ... do something to fill res ... 
    cout << &res << endl; // PRINT POINTER 
    return res; 
} 

int main(int argc, char **argv) { 
    std::vector<int> myvec = fill_list(); 
    cout << &myvec << endl; // PRINT POINTER 
    return 0; 
} 

दो "प्रिंट पॉइंटर" लाइनें दोनों मामलों में समान सूचक प्रिंट करेंगी।

उपरोक्त में वेक्टर मायवेक और वेक्टर रेज एक ही भंडारण के साथ एक ही वेक्टर होगा। कोई कॉपी कन्स्ट्रक्टर या चालक कन्स्ट्रक्टर नहीं कहा जाएगा। एक अर्थ में res और myvec एक ही वस्तु के दो उपनाम होंगे।

यह एक चालक कन्स्ट्रक्टर का उपयोग करने से भी बेहतर है। myvec का निर्माण किया गया है और जगह में "भरा" है।

कंपाइलर को "इनस्थल" मोड में फ़ंक्शन को संकलित करके कॉलर स्टैक फ्रेम में कॉलर स्टैक फ्रेम में तत्काल स्टैक स्थिति को ओवरले करने के द्वारा प्राप्त किया जाता है, और कैली रिटर्न के बाद बस इसे छोड़ देता है।

इस परिस्थिति में हम कहते हैं कि निर्माता elided है। अधिक जानकारी के लिए यहाँ देखें:

http://en.wikipedia.org/wiki/Return_value_optimization

घटना है कि आप की तुलना में एक XValue में एक वापसी-दर-मूल्य परिणाम के रूप में एक गैर-निर्माता संदर्भ में fill_list का परिणाम बताए गए थे, में (छोटे के लिए "समाप्ति" मान, एक प्रकार का रावल्यू), लक्ष्य चर के चाल असाइनमेंट ऑपरेटर को उपलब्ध होने पर वरीयता दी जाएगी।

+0

"इस परिस्थिति में हम कहते हैं कि प्रति निर्माण का विस्तार किया गया है।" ध्यान दें कि यह निर्माण को स्थानांतरित करने पर भी लागू होता है। –

+0

हां, दोनों। "कॉपी निर्माण" और "निर्माण निर्माण" दोनों के लिए सामूहिक शब्द क्या है .. वह अनुमान लगाता है/प्रतिलिपि बनाता है मुझे लगता है कि –

+0

"*' T && 'केवल ** अधिभार रिज़ॉल्यूशन ** के लिए आवश्यक है। *" यह एक बहुत बड़ा ओवरम्प्लिफिकेशन है। – ildjarn

0

रिटर्न स्टेटमेंट एक त्रुटि है क्योंकि आप एक लालू संदर्भ (रिटर्न प्रकार) को एक लवल्यू (वेक्टर रेस) में बांधने का प्रयास करते हैं। एक रावल्यू संदर्भ केवल एक रावल्यू के लिए बाध्य किया जा सकता है।

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

यदि आप रिटर्न स्टेटमेंट के दौरान कॉपी निर्माण से बचना चाहते हैं, तो केवल एक गैर-संदर्भ प्रकार का उपयोग कर कॉपी एलिशन नामक सुविधा के कारण पहले से ही काम कर सकता है। आपके fill_list फ़ंक्शन में वेक्टर रेज सीधे आपके मुख्य फ़ंक्शन में वेक्टर myvec में बनाया जा सकता है, इसलिए कोई भी प्रतिलिपि या चाल निर्माण नहीं किया जाता है। लेकिन मानक द्वारा आवश्यक इस सुविधा की अनुमति नहीं है, कुछ संकलक कुछ संकलक में छोड़ा नहीं गया है।