तो, मान लीजिए कि आपने है:
A compute()
{
A v;
…
return v;
}
और आप कर रहे हैं:
A a = compute();
दो स्थानान्तरण (कॉपी या स्थानांतरित) है कि इस अभिव्यक्ति में शामिल कर रहे हैं। सबसे पहले फ़ंक्शन में v
द्वारा निर्दिष्ट ऑब्जेक्ट को फ़ंक्शन के परिणाम में स्थानांतरित किया जाना चाहिए, यानी compute()
अभिव्यक्ति द्वारा दान किया गया मान। के कहते हैं कि स्थानांतरण 1. फिर, इस अस्थायी वस्तु वस्तु a
से दर्शाया जाता है बनाने के लिए स्थानांतरित कर रहा है - स्थानांतरण 2.
कई मामलों में, दोनों स्थानांतरण 1 और 2 संकलक द्वारा elided जा सकता है - वस्तु v
सीधे निर्माण किया है a
के स्थान पर और कोई स्थानांतरण आवश्यक नहीं है। कंपाइलर को इस उदाहरण में स्थानांतरण 1 के लिए नामांकित रिटर्न वैल्यू ऑप्टिमाइज़ेशन का उपयोग करना होगा, क्योंकि वापस आने वाली ऑब्जेक्ट का नाम दिया गया है। अगर हम प्रतिलिपि/चाल elision अक्षम करते हैं, हालांकि, प्रत्येक स्थानांतरण में ए के प्रतिलिपि निर्माता या उसके चालक कन्स्ट्रक्टर को कॉल शामिल है। अधिकांश आधुनिक कंपाइलरों में, संकलक देखेंगे कि v
नष्ट होने वाला है और यह पहले इसे वापसी मूल्य में ले जाएगा। फिर यह अस्थायी वापसी मूल्य a
में ले जाया जाएगा। यदि A
में कोई चालक कन्स्ट्रक्टर नहीं है, तो इसकी बजाय प्रतिस्थापन दोनों के लिए कॉपी किया जाएगा।
अब पर नज़र करने देता है:
A compute(A&& v)
{
return v;
}
हम वापस लौट रहे हैं मूल्य संदर्भ समारोह में पारित किया जा रहा से आता है। कंपाइलर यह नहीं मानता कि v
एक अस्थायी है और यह से स्थानांतरित करना ठीक है। इस मामले में, स्थानांतरण 1 एक प्रतिलिपि होगी। फिर स्थानांतरण 2 एक कदम होगा - यह ठीक है क्योंकि लौटाया गया मूल्य अभी भी एक अस्थायी है (हमने संदर्भ वापस नहीं किया है)। लेकिन चूंकि हम जानते हैं है कि हम एक वस्तु है कि हम से स्थानांतरित कर सकते हैं लिया है, क्योंकि हमारे पैरामीटर एक rvalue संदर्भ है, हम स्पष्ट रूप से std::move
के साथ एक अस्थायी रूप v
के इलाज के लिए संकलक बता सकते हैं:
A compute(A&& v)
{
return std::move(v);
}
अब ट्रांसफर 1 और ट्रांसफर 2 दोनों चलेंगे।
कारण है कि संकलक स्वचालित रूप से v
, A&&
के रूप में परिभाषित का इलाज नहीं करता है, के रूप में एक rvalue सुरक्षा से एक है। इसे समझने के लिए यह बहुत बेवकूफ नहीं है। एक बार ऑब्जेक्ट का नाम हो जाने के बाद, इसे आपके कोड में कई बार संदर्भित किया जा सकता है। पर विचार करें:
A compute(A&& a)
{
doSomething(a);
doSomethingElse(a);
}
तो a
स्वचालित रूप से एक rvalue के रूप में इलाज किया गया था, doSomething
, अपनी हिम्मत बाहर चीर के लिए स्वतंत्र होगा जिसका अर्थ है कि a
doSomethingElse
को पारित किया जा रहा अमान्य हो सकता है। भले ही doSomething
ने मूल्य के आधार पर अपना तर्क लिया, तो ऑब्जेक्ट को आगे ले जाया जाएगा और इसलिए अगली पंक्ति में अमान्य हो जाएगा। इस समस्या से बचने के लिए, नामित रावल संदर्भ संदर्भ हैं। इसका मतलब है कि doSomething
कहा जाता है, a
सबसे खराब रूप से प्रतिलिपि बनाई जाएगी, अगर केवल lvalue संदर्भ द्वारा नहीं लिया गया - यह अभी भी अगली पंक्ति में मान्य होगा।
यह कहने के लिए compute
के लेखक पर है, "ठीक है, अब मैं इस मान को स्थानांतरित करने की अनुमति देता हूं, क्योंकि मुझे पता है कि यह एक अस्थायी वस्तु है"। आप std::move(a)
कहकर ऐसा करते हैं। उदाहरण के लिए, आप doSomething
एक प्रति दे और फिर इसे से स्थानांतरित करने के लिए अनुमति देते हैं doSomethingElse
सकता है:
A compute(A&& a)
{
doSomething(a);
doSomethingElse(std::move(a));
}
हैं कि विवादित लेख का लिंक है? –
[संबंधित एफएक्यू] (http://stackoverflow.com/questions/3106110/) – fredoverflow
http://cpp-next.com/archive/2009/09/making-your-next-move/, यह एक श्रृंखला है rvalue संदर्भ – StereoMatching