Std :: Move and std :: आगे के बीच क्या अंतर है


160

मैंने इसे यहाँ देखा: मूव कन्स्ट्रक्टर को बेस-क्लास मूव कंस्ट्रक्टर कहते हैं

क्या कोई समझा सकता है:

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

1
इन दो संबंधित प्रश्नों को भी देखें: क्या मुझे std :: Move या std :: का उपयोग मूवमेंट / असाइनमेंट ऑपरेटरों में करना चाहिए? और std :: आगे का काम कैसे करता है? (डुप्लीकेट प्रश्न के रूप में भी)।
Xeo

"इसके बारे में आसानी से कैसे सोचें, और कब उपयोग करें" जिसका उपयोग आप moveतब करते हैं जब आप एक मूल्य को स्थानांतरित करना चाहते हैं , और forwardजब आप संपूर्ण प्रशिक्षण का उपयोग करना चाहते हैं। यह रॉकेट साइंस नहीं है;)
निकोल बोल्स

चाल () बिना शर्त डाली जहां आगे बढ़ा दिया गया है) उस पैरामीटर के आधार पर डाली जाती है जो बीत चुका है।
Raaa__M

जवाबों:


159

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

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

वर्णन करने के लिए :

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सीधे उपयोग करना चाहिए और जो आप कर रहे हैं उसका एक अच्छा विवरण लिखें।


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

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

मैंने एक अलग प्रश्न के रूप में एक उदाहरण पोस्ट किया: stackoverflow.com/questions/20616958/…
जियोफ़ रोमर

हम्म, इसलिए यदि मैं इसे सही ढंग से समझता हूं, तो इसका मतलब है कि मैं एक एकल फ़ंक्शन को आगे लिख सकता हूं () जहां फॉरवर्ड (5) 5 पर संचालित होता है जैसे कि मैंने इसे मूल्य से पारित किया जहां आगे (एक्स) एक्स पर संचालित होता है जैसे कि मैंने इसे पास किया एक अधिभार को स्पष्ट रूप से लिखे बिना संदर्भ।
इहानी जू १14

@ जिहनी हां, यह विचार है! लेकिन इसे केवल एक सामान्य कार्य नहीं, बल्कि एक टेम्पलेट होना चाहिए।
पोटाटोज़वाटर

63

दोनों std::forwardऔर std::moveकुछ नहीं बल्कि जातियां हैं।

X x;
std::move(x);

उपरोक्त xप्रकार X के लवल्यू एक्सप्रेशन को टाइप X के रिवेल्यू एक्सप्रेशन (सटीक होने के लिए एक एक्सवल्यू) कास्ट करता है। moveभी एक स्वीकार कर सकते हैं:

std::move(make_X());

और इस मामले में यह एक पहचान समारोह है: टाइप X का एक अंतराल लेता है और प्रकार X का एक अंतराल लौटाता है।

साथ std::forwardआप कुछ हद तक गंतव्य का चयन कर सकते हैं:

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

xटाइप X के लैवल्यू एक्सप्रेशन को टाइप Y की अभिव्यक्ति के लिए कास्ट करता है। Y क्या हो सकता है, इस पर अड़चनें हैं।

Y, X का एक सुलभ आधार हो सकता है, या X के आधार का संदर्भ Y हो सकता है। X, या X का संदर्भ हो सकता है। कोई cv-क्वालिफायर को दूर नहीं कर सकता है forward, लेकिन कोई cv-qualifiers जोड़ सकता है। Y एक प्रकार नहीं हो सकता है जो एक्स से केवल एक परिवर्तनीय आधार रूपांतरण को छोड़कर केवल परिवर्तनीय है।

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

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

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


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

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

21

std::forwardएक पैरामीटर को ठीक उसी तरह से अग्रेषित करने के लिए उपयोग किया जाता है जिस तरह से यह एक फ़ंक्शन को पास किया गया था। जैसा यहाँ दिखाया गया है:

कब उपयोग करें std :: आगे के तर्कों के लिए आगे?

std::moveसंभवतया एक मूव कंस्ट्रक्टर या फ़ंक्शन को स्वीकार करने वाले फ़ंक्शन से मेल खाता है, जो एक प्रतिद्वंद्विता के रूप में एक वस्तु का उपयोग करता है। यह ऐसा करता है कि std::move(x)भले xही अपने आप में कोई प्रतिद्वंद्विता न हो।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.