2013-09-07 2 views
19

GoingNative 2013 देखने के बाद, मैं समझ गया कि सिंक तर्क हमेशा मूल्य द्वारा पारित और std::move साथ ले जाया जाना चाहिए। TestMove::ctor इस मुहावरे को लागू करने का सही तरीका है? क्या कोई ऐसा मामला है जहां TestConstRef::ctor बेहतर/अधिक कुशल है?क्या मुझे हमेशा 'सिंक' कन्स्ट्रक्टर या सेटर तर्क पर जाना चाहिए?


मामूली सेटर्स के बारे में क्या? क्या मुझे निम्नलिखित मुहावरे का उपयोग करना चाहिए या const std::string& पास करना चाहिए?

struct TestSetter { 
    std::string str; 
    void setStr(std::string mStr) { str = std::move(str); } 
}; 
+0

वह दावा मेरे लिए संदिग्ध लगता है। 'कॉन्स्ट एंड' द्वारा पास करना और फिर प्रारंभ करना एक प्रतिलिपि कन्स्ट्रक्टर को कॉल करेगा। मूल्य और आगे बढ़ने से एक कॉपी कन्स्ट्रक्टर को एक चाल असाइनमेंट ऑपरेटर के बाद कॉल किया जाएगा। – Yuushi

+0

@ युसुशी: सामान्यतः, अधिकांश वर्गों का चालक कन्स्ट्रक्टर लगभग मुफ़्त है (एक स्वैप के बराबर)। साथ ही, आप उन मामलों को भूल रहे हैं जहां आप अस्थायी (या एक स्थानांतरित चर से) तर्क को प्रारंभ करते हैं। –

+0

@MatthieuM। मुझे एहसास है कि चालक कन्स्ट्रक्टर आमतौर पर लगभग मुफ्त है। हालांकि, यदि आप परिवर्तनीय से अस्थायी/स्थानांतरित हो रहे हैं, तो इसे स्पष्ट रूप से एक रावल्यू संदर्भ लेने के लिए क्यों न घोषित करें? – Yuushi

उत्तर

18

सरल उत्तर है: हाँ।


कारण या तो आप (एक अस्थायी से) ले जाने के लिए या (एक एल-मूल्य से) एक प्रतिलिपि बनाने की आवश्यकता हो सकती है अगर आप मान द्वारा की दुकान है, साथ ही काफी सरल है। आइए जांच करें कि दोनों स्थितियों में दोनों स्थितियों में क्या होता है।

एक अस्थायी

  • से यदि आप स्थिरांक-रेफरी द्वारा तर्क लेते हैं, अस्थायी स्थिरांक-रेफरी के लिए बाध्य है और फिर से ले जाया जा सकता है, इस प्रकार आप अंत एक (बेकार) बनाने प्रति।
  • यदि आप मूल्य से तर्क लेते हैं, तो मूल्य अस्थायी (चलती) से प्रारंभ होता है, और फिर आप स्वयं तर्क से आगे बढ़ते हैं, इस प्रकार कोई प्रतिलिपि नहीं बनाई जाती है।

एक सीमा: एक कुशल चालक-निर्माता (जैसे std::array<T, N>) के बिना एक वर्ग क्योंकि तब आपने एक की बजाय दो प्रतियां की थीं।

एक एल-मूल्य से (या स्थिरांक अस्थायी है, लेकिन जो कि क्या करना होगा ...)

  • अगर आप स्थिरांक-रेफरी द्वारा तर्क लेते हैं, कोई बात नहीं होता है, और उसके बाद आप इसे कॉपी (इससे आगे नहीं बढ़ सकता), इस प्रकार एक प्रतिलिपि बनाई जाती है।
  • यदि आप मूल्य से तर्क लेते हैं, तो आप इसे तर्क में कॉपी करते हैं और फिर उससे आगे बढ़ते हैं, इस प्रकार एक प्रतिलिपि बनाई जाती है।

एक सीमा: वही ... कक्षाएं जिसके लिए चलती है प्रतिलिपि बनाने के समान है।

तो, सरल जवाब यह है कि ज्यादातर मामलों में, एक सिंक का उपयोग करके आप अनावश्यक प्रतियों से बचते हैं (उन्हें चाल से बदलते हैं)।

एकल सीमा कक्षाएं है जिसके लिए चालक कन्स्ट्रक्टर प्रतिलिपि के रूप में महंगा (या महंगी के रूप में) है; जिस मामले में एक प्रतिलिपि के बजाय दो चालें होती हैं वह "सबसे खराब" होती है। शुक्र है, इस तरह के वर्ग दुर्लभ हैं (सरणी एक मामले हैं)।

+0

स्पष्ट उत्तर के लिए धन्यवाद! क्या यह छोटे सेटर्स पर भी लागू होता है? (मूल पोस्ट में दूसरा उदाहरण, बाद में संपादित) –

+0

"हां" किस प्रश्न का उत्तर है? :) –

+0

@VittorioRomeo: किसी भी विधि से जो तर्क की एक प्रति बनाता है, चाहे वह कन्स्ट्रक्टर, सेटर, या केवल कुछ विनाशकारी गणना हो। –

10

थोड़ा देर से, के रूप में यह सवाल पहले से ही स्वीकार किए जाते हैं जवाब है, लेकिन वैसे भी ... यहाँ एक विकल्प है:

struct Test { 
    std::string str; 
    Test(std::string&& mStr) : str{std::move(mStr)} { } // 1 
    Test(const std::string& mStr) : str{mStr} { } // 2 
}; 

क्यों कि बेहतर होगा?एक अस्थायी (मामले // 1)

केवल एक कदम-निर्माता str के लिए कहा जाता है से

: दो मामलों पर विचार करें।

एक एल-मूल्य से (मामले // 2)

केवल एक प्रतिलिपि-निर्माता str के लिए कहा जाता है।

शायद यह उससे बेहतर नहीं हो सकता है।

लेकिन रुकिए, अधिक है:

कोई अतिरिक्त कोड फोन करने वाले की तरफ से उत्पन्न होता है! कॉपी- या मूव-कन्स्ट्रक्टर (जिसे रेखांकित किया जा सकता है या नहीं) का कॉलिंग अब कॉल किए गए फ़ंक्शन के कार्यान्वयन में रह सकता है (यहां: Test::Test) और इसलिए उस कोड की केवल एक प्रति आवश्यक है। यदि आप बाय-वैल्यू पैरामीटर पास करते हैं, तो कॉलर फ़ंक्शन को पारित ऑब्जेक्ट का उत्पादन करने के लिए ज़िम्मेदार है। यह बड़ी परियोजनाओं में शामिल हो सकता है और यदि संभव हो तो मैं इससे बचने की कोशिश करता हूं।

+0

जहां तक ​​मैं समझता हूं, प्रदर्शन और कोडजन के संदर्भ में यह सबसे अच्छा संभव दृष्टिकोण है, लेकिन एक अतिरिक्त कन्स्ट्रक्टर की आवश्यकता है - सही? –

+0

@VittorioRomeo: हाँ, यह कमी है - आपको हमेशा दो ओवरलोड की आवश्यकता होती है। यदि किसी विधि में कई पैरामीटर हैं, तो यह काफी बोझ हो सकता है और इसके मूल्य-दर-मानकों पर वापस जाने पर विचार करना उचित है। –

+3

ईमानदार होने के लिए, एक भाषा दोष की तरह लगता है। आवश्यक सीटीआर की संख्या तेजी से बढ़ सकती है ... क्या इसे ठीक करने का कोई प्रस्ताव है? –

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