2015-04-18 5 views
10

मैं एसटीएल द्वारा "Don’t Help the Compiler" बात है, जहां वह स्लाइड 26 पर एक समान उदाहरण है देख रहा हूँ:संगत प्रकार लौटने पर स्पष्ट std :: move की आवश्यकता क्यों है?

struct A 
{ 
    A() = default; 
    A(const A&) { std::cout << "copied" << std::endl; } 
    A(A&&) { std::cout << "moved" << std::endl; } 
}; 

std::pair<A, A> get_pair() 
{ 
    std::pair<A, A> p; 
    return p; 
} 

std::tuple<A, A> get_tuple() 
{ 
    std::pair<A, A> p; 
    return p; 
} 

std::tuple<A, A> get_tuple_moved() 
{ 
    std::pair<A, A> p; 
    return std::move(p); 
} 
इस के साथ

, निम्नलिखित कॉल:

get_pair(); 
get_tuple(); 
get_tuple_moved(); 

इस उत्पादन का उत्पादन:

moved 
moved 
copied 
copied 
moved 
moved 

See MCVE in action

get_pair का परिणाम स्थानांतरित है, जैसा कि अपेक्षित है। एक कदम भी एनआरवीओ द्वारा पूरी तरह से elided किया जा सकता है, लेकिन यह वर्तमान प्रश्न के विषय से बाहर है।

get_tuple_moved का परिणाम भी स्थानांतरित किया गया है, जिसे स्पष्ट रूप से ऐसा माना जाता है। हालांकि, get_tuple का परिणाम प्रति-निर्मित है, जो मेरे लिए पूरी तरह से स्पष्ट नहीं है।

मैंने सोचा कि return कथन को पारित किसी भी अभिव्यक्ति को move पर अंतर्निहित माना जा सकता है, क्योंकि संकलक जानता है कि यह किसी भी तरह से गुंजाइश से बाहर निकलने वाला है। ऐसा लगता है कि मैं गलत हूं। क्या कोई स्पष्टीकरण दे सकता है, यहां क्या चल रहा है?

भी देखें संबंधित है, लेकिन विभिन्न प्रश्न: When should std::move be used on a function return value?

+0

क्या आपने कॉपी एलिशन को अक्षम किया था? इसके अलावा, एक असली एमसीवीई बेहतर पोस्ट करें। – juanchopanza

+2

@juanchopanza यह वास्तव में एक असली एमसीवीई है, बस 'मुख्य() 'में कॉलिंग विधियों को डालें। 'Get_tuple' और' get_tuple_moved' के लिए व्यवहार आरवीओ के बावजूद समान है, जबकि 'get_pair' प्रभावित होता है। – Mikhail

+1

@ मिखाइल: तो यह वास्तव में एक असली एमसीवीई नहीं है (क्योंकि इसे कॉपी और पेस्ट की तुलना में अधिक काम की आवश्यकता है, हालांकि इसमें से केवल एक छोटा सा) :-) –

उत्तर

8

get_tuple में वापसी कथन() जा चाल-निर्माता का उपयोग कर कॉपी-प्रारंभ करना चाहिए, लेकिन नहीं बदले अभिव्यक्ति के प्रकार और वापसी प्रकार कर के बाद से मैच, कॉपी-कन्स्ट्रक्टर को इसके बजाय चुना जाता है। सी ++ 14 में एक बदलाव आया था जहां अब ओवरलोड रिज़ॉल्यूशन का प्रारंभिक चरण है जो रिटर्न स्टेटमेंट को रावल्यू के रूप में मानता है जब यह शरीर में घोषित एक स्वचालित चर होता है।

प्रासंगिक शब्दों [class.copy] में पाया जा सकता/p32:

जब एक कॉपी/कदम आपरेशन के इलिजन के लिए मानदंडों को पूरा कर रहे हैं, [..], या जब में अभिव्यक्ति एक रिटर्न स्टेटमेंट एक (संभावित रूप से ब्रांडेड) आईडी-अभिव्यक्ति है जो शरीर में [..] में घोषित स्वत: संग्रहण अवधि के साथ एक ऑब्जेक्ट का नाम देता है, प्रतिलिपि के लिए कन्स्ट्रक्टर का चयन करने के लिए ओवरलोड रिज़ॉल्यूशन पहले किया जाता है जैसे ऑब्जेक्ट को नामित किया गया था rvalue।

तो सी ++ 14 में सभी उत्पादन बजना और जीसीसी के ए

ट्रंक संस्करणों की चाल-निर्माता से आ जाना चाहिए पहले से ही इस परिवर्तन को लागू करने। सी ++ 11 मोड में एक ही व्यवहार प्राप्त करने के लिए आपको रिटर्न स्टेटमेंट में एक स्पष्ट std :: move() का उपयोग करना होगा।

+0

तो मूल रूप से, यह एक गैर-मानक व्यवहार है, जो कम से कम 'gcc-4.9.2' और 'विजुअल स्टूडियो 2015 सीटीपी 6' के लिए होता है? – Mikhail

+2

@ मिखाइल यह सी ++ 11 में मानक व्यवहार है, लेकिन वे नवीनतम मानक (सी ++ 14) के अनुरूप नहीं हैं। – 0x499602D2

+0

क्लैंग ने वास्तव में इस बदलाव को अभी तक लागू नहीं किया है, लेकिन जीसीसी में है। – 0x499602D2

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