2015-03-09 31 views
9

std::move के कार्यान्वयन मूल रूप से इस तरह दिखता है:std :: move आगे का संदर्भ क्यों लेता है?

template<typename T> 
typename std::remove_reference<T>::type&& 
move(T&& t) 
{ 
    return static_cast<typename std::remove_reference<T>::type&&>(t); 
} 

ध्यान दें कि std::move के पैरामीटर एक सार्वभौमिक संदर्भ है (यह भी एक अग्रेषण संदर्भ के रूप में जाना है, लेकिन हम यहाँ अग्रेषण नहीं हैं)।

std::string a, b, c; 
// ... 
foo(std::move(a));  // fine, a is an lvalue 
foo(std::move(b + c)); // nonsense, b + c is already an rvalue 

लेकिन चूंकि std::move के पूरे मुद्दे एक rvalue को कास्ट करने के लिए है, इसलिए हम भी std::move rvalues ​​करने की अनुमति है: यह तुम दोनों lvalues ​​और rvalues ​​std::move कर सकते हैं, है? std::move केवल लालच स्वीकार करेगा अगर यह अधिक समझ में नहीं आता है?

template<typename T> 
T&& 
move(T& t) 
{ 
    return static_cast<T&&>(t); 
} 

तब बकवास अभिव्यक्ति std::move(b + c) संकलन-समय त्रुटि उत्पन्न करेगी।

std::move के उपरोक्त कार्यान्वयन को शुरुआती लोगों के लिए समझना बहुत आसान होगा, क्योंकि कोड ठीक वही करता है जो ऐसा लगता है: यह एक लालसा लेता है और एक रैल्यू देता है। आपको सार्वभौमिक संदर्भ, संदर्भ ढहने और मेटा कार्यों को समझने की आवश्यकता नहीं है।

तो std::move क्यों था lvalues ​​और rvalues ​​दोनों लेने के लिए बनाया गया था?

+0

मेरा त्वरित अनुमान यह होगा कि जब आप अपने आस-पास की चीजों को स्थानांतरित करने के लिए कोड लिखते हैं तो यह लगातार नहीं रहना चाहती कि आपके चर याताएं हैं या नहीं, आप बस इसे करना चाहते हैं। – sim642

+3

क्योंकि यह बिना किसी शर्त के रावल्यू के लिए दोनों lvalue और rvalue डालने के लिए डिज़ाइन किया गया है। –

+0

@ 6502 एप्लिकेशन डेवलपर की तुलना में लाइब्रेरी डेवलपर के लिए यह प्रश्न या विवरण अधिक उपयोगी है। एप्लिकेशन डेवलपर बस खुशी से std :: move() को कॉल कर सकता है; और काम के साथ मिलते हैं। बेशक यह समझना चाहिए कि स्थानीय चर को स्थानांतरित करने से राज्य अमान्य हो जाएगा। अन्यथा यहां सिर तोड़ने के लिए कुछ नहीं। – Jagannath

उत्तर

9

यहां कुछ उदाहरण चरम करने के लिए सरल है:

#include <iostream> 
#include <vector> 

template<typename T> 
T&& my_move(T& t) 
{ 
    return static_cast<T&&>(t); 
} 

int main() 
{ 
    std::vector<bool> v{true}; 

    std::move(v[0]); // std::move on rvalue, OK 
    my_move(v[0]); // my_move on rvalue, OOPS 
} 

मामले की तरह ऊपर जब जो विशेषज्ञताओं है कि वापसी प्रॉक्सी वस्तुओं (rvalues) है कंटेनरों का इस्तेमाल किया, सामान्य कोड में दिखाई दे सकते हैं उदाहरण के लिए, और आप कर सकते हैं यह नहीं पता कि ग्राहक विशेषज्ञता का उपयोग करेगा या नहीं, इसलिए आप चलने वाले अर्थशास्त्र के लिए बिना शर्त समर्थन चाहते हैं।

+3

उपरोक्त। यहां एक असली दुनिया का उदाहरण दिया गया है: https://github.com/llvm-mirror/libcxx/blob/master/include/algorithm#L2451 –

2

यह चोट नहीं पहुंचाता है।

आप बस एक गारंटी स्थापित कर रहे हैं कि कोड परिणामस्वरूप एक रावल्यू के रूप में व्यवहार करेगा। आप निश्चित रूप से std :: move लिख सकते हैं इस तरह से कि यह किसी चीज से निपटने में त्रुटिपूर्ण हो जो पहले से ही एक रावल्यू है, लेकिन लाभ क्या है?

जेनेरिक कोड में, जहां आपको जरूरी नहीं है कि आप किस प्रकार के काम के साथ काम करने जा रहे हैं, अभिव्यक्ति में क्या लाभ होगा, यदि आप रावल्यू के अलावा कुछ और नहीं करते हैं :: चाल "हर जगह plastered जब आप बस कह सकते हैं" मैं वादा करता हूँ कि हम इसे एक रावल्यू के रूप में सोच सकते हैं "।

आपने इसे स्वयं कहा, यह एक कलाकार से अधिक कुछ नहीं है। अगर तर्क पहले से ही इच्छित प्रकार से मेल खाता है तो _cast ऑपरेशंस भी असफल हो सकता है?

+0

वह अंतिम वाक्य बहुत ही भरोसेमंद है। बहुत बढ़िया। +1 –

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