2012-03-12 7 views
124

:: std :: चाल और एसटीडी के बीच अंतर मैं यहाँ देखा है: Move Constructor calling base-class Move Constructorक्या आगे

कोई समझा सकते हैं:

  1. std::move और std::forward के बीच का अंतर, कुछ कोड उदाहरण के साथ अधिमानतः?
  2. इसके बारे में सोचने के लिए आसानी से, और जब उपयोग करने के लिए जो
+1

इन दो संबंधित प्रश्नों को भी देखें: [क्या मुझे std :: move या std :: move ctors/असाइनमेंट ऑपरेटर में आगे बढ़ाना चाहिए?] (Http://stackoverflow.com/q/8860233/500104) और [कैसे करता है std :: आगे काम?] (http://stackoverflow.com/q/8526598/500104) (साथ ही डुप्लिकेट प्रश्न के रूप में)। – Xeo

+0

"इसके बारे में आसानी से कैसे सोचें, और जब आप * चाल * को स्थानांतरित करना चाहते हैं, तो आप 'move' का उपयोग करते हैं, और 'अग्रेषित' जब आप सही अग्रेषण का उपयोग करना चाहते हैं। यह यहां रॉकेट विज्ञान नहीं है;) –

+0

चाल() बिना शर्त कास्ट करें जहां आगे() पारित पैरामीटर के आधार पर कास्ट प्रदर्शन करते हैं। –

उत्तर

115

std::move एक वस्तु लेता है और आपको इसे अस्थायी (एक रावल्यू) के रूप में पेश करने की अनुमति देता है। यद्यपि यह एक अर्थपूर्ण आवश्यकता नहीं है, आम तौर पर एक रावल्यू के संदर्भ को स्वीकार करने वाला एक कार्य इसे अमान्य कर देगा।जब आप std::move देखते हैं, तो यह इंगित करता है कि ऑब्जेक्ट का मान बाद में उपयोग नहीं किया जाना चाहिए, लेकिन आप अभी भी एक नया मान असाइन कर सकते हैं और इसका उपयोग जारी रख सकते हैं।

std::forward में एक ही उपयोग का मामला है: एक श्रेणीबद्ध फ़ंक्शन पैरामीटर (फ़ंक्शन के अंदर) को मूल्य श्रेणी (lvalue या rvalue) में कॉल करने के लिए उपयोग किए जाने वाले कॉलर को डालने के लिए। यह रैवल्यू तर्कों को राजस्व के रूप में पारित करने की अनुमति देता है, और अंतराल को "पूर्ण अग्रेषण" नामक एक योजना के रूप में पारित किया जा सकता है।

illustrate करने के लिए:

void overloaded(int const &arg) { std::cout << "by lvalue\n"; } 
void overloaded(int && arg) { std::cout << "by rvalue\n"; } 

template< typename t > 
/* "t &&" with "t" being template param is special, and adjusts "t" to be 
    (for example) "int &" or non-ref "int" so std::forward knows what to do. */ 
void forwarding(t && arg) { 
    std::cout << "via std::forward: "; 
    overloaded(std::forward<t>(arg)); 
    std::cout << "via std::move: "; 
    overloaded(std::move(arg)); // conceptually this would invalidate arg 
    std::cout << "by simple passing: "; 
    overloaded(arg); 
} 

int main() { 
    std::cout << "initial caller passes rvalue:\n"; 
    forwarding(5); 
    std::cout << "initial caller passes lvalue:\n"; 
    int x = 5; 
    forwarding(x); 
} 

हावर्ड का उल्लेख है, वहाँ भी समानता के रूप में इन दोनों कार्यों बस प्रकार संदर्भ के लिए डाली है। लेकिन इन विशिष्ट उपयोग मामलों के बाहर (जो रैल्यू संदर्भ के उपयोग की 99.9% उपयोग को कवर करता है), आपको सीधे static_cast का उपयोग करना चाहिए और आप जो कर रहे हैं उसका एक अच्छा स्पष्टीकरण लिखना चाहिए।

+0

मुझे यकीन नहीं है कि यह सटीक है कि 'std :: forward' का _only_ उपयोग केस फ़ंक्शन तर्कों का पूर्ण अग्रेषण है। मैंने परिस्थितियों में भाग लिया है जहां मैं ऑब्जेक्ट सदस्यों की तरह अन्य चीजों को पूरी तरह से आगे बढ़ाना चाहता हूं। –

+0

@GeoffRomer पैरामीटर के सदस्य? आपके पास कोई उदाहरण है? – Potatoswatter

+0

मैंने एक अलग प्रश्न के रूप में एक उदाहरण पोस्ट किया: http://stackoverflow.com/questions/20616958/stdforward-without-perfect-forwarding –

19

std::forwardआगे के लिए एक पैरामीटर वास्तव में जिस तरह से यह एक समारोह को पारित किया गया था प्रयोग किया जाता है। बस यहाँ दिखाया गया है पसंद:

When to use std::forward to forward arguments?

std::move एक rvalue के रूप में एक वस्तु प्रदान करता है का उपयोग करना, संभवतः एक चाल निर्माता या एक समारोह rvalues ​​को स्वीकार करने से मिलान करने के। यह std::move(x) के लिए भी है यदि x अपने आप से एक रावल नहीं है।

51

std::forward और std::move दोनों कुछ भी नहीं हैं।

X x; 
std::move(x); 

ऊपर प्रकार एक्स (एक XValue सटीक होना करने के लिए) के एक rvalue अभिव्यक्ति के प्रकार एक्स के lvalue अभिव्यक्ति x डाले। move भी एक rvalue स्वीकार कर सकते हैं:

std::move(make_X()); 

और इस मामले में यह एक पहचान समारोह है: प्रकार एक्स के एक rvalue लेता है और प्रकार एक्स के एक rvalue रिटर्न

std::forward साथ

आप के लिए गंतव्य का चयन कर सकते हैं कुछ हद:

X x; 
std::forward<Y>(x); 

प्रकार वाई की अभिव्यक्ति के लिए प्रकार एक्स के lvalue अभिव्यक्ति x डाले Y क्या हो सकता है पर कमी कर रहे हैं।

वाई एक्स का एक सुलभ आधार हो सकता है, या एक्स के आधार के संदर्भ में वाई हो सकता है, या एक्स का संदर्भ हो सकता है। कोई forward के साथ सीवी-क्वालीफायर को नहीं हटा सकता है, लेकिन कोई भी सीवी- क्वालिफायर। वाई एक प्रकार का नहीं हो सकता है जो एक्स से केवल परिवर्तनीय है, एक सुलभ आधार रूपांतरण के अलावा।

यदि वाई एक लवल्यू संदर्भ है, तो परिणाम एक अंतराल अभिव्यक्ति होगी। यदि वाई एक लवण संदर्भ नहीं है, तो परिणाम एक रैवल्यू (सटीक होना चाहिए) अभिव्यक्ति होगी।

forward केवल एक रावल्यू तर्क ले सकता है यदि वाई एक लवल्यू संदर्भ नहीं है। यही है, आप lvalue के लिए एक rvalue नहीं डाल सकते हैं। यह सुरक्षा कारणों से है क्योंकि ऐसा करने से आम तौर पर खतरनाक संदर्भ होते हैं। लेकिन रैवल्यू के लिए एक रैल्यू कास्टिंग ठीक है और अनुमति है।

यदि आप किसी ऐसी चीज़ को निर्दिष्ट करने का प्रयास करते हैं जिसकी अनुमति नहीं है, तो त्रुटि समय पर संकलित समय पर पकड़ा जाएगा, समय नहीं चलाया जाएगा।

+0

यदि मैं 'std :: forward' का उपयोग कर किसी फ़ंक्शन पर ऑब्जेक्ट को पूरी तरह से अग्रेषित करता हूं, तो उस फ़ंक्शन को निष्पादित करने के बाद, क्या मैं उस ऑब्जेक्ट का उपयोग कर सकता हूं? मुझे पता है कि, 'std :: move' के मामले में, यह एक अनिर्धारित व्यवहार है। – iammilind

+0

'move' के संबंध में: https://stackoverflow.com/a/7028318/576911 'आगे' के लिए, यदि आप एक अंतराल में गुजरते हैं, तो आपके एपीआई को प्रतिक्रिया देनी चाहिए जैसे कि यह एक लाभा प्राप्त करता है। आम तौर पर इसका मतलब है कि मान असम्बद्ध हो जाएगा। लेकिन अगर यह एक गैर-कॉन्स लैवल्यू है, तो आपके एपीआई ने इसे संशोधित कर दिया होगा। यदि आप एक रावल्यू में गुजरते हैं, तो इसका सामान्य अर्थ यह है कि आपका एपीआई इससे आगे बढ़ सकता है, और इस प्रकार https://stackoverflow.com/a/7028318/576911 लागू होगा। –