2012-11-15 20 views
6

मैं another question में पढ़ा है कि यह :: प्रारंभकर्ता सूची में प्रत्येक सदस्य के लिए कदम है क्योंकि अगर सदस्य किसी अन्य वस्तु तो होना करने के लिए है कि वस्तुओं निर्माता को स्थानांतरित होता है एसटीडी अच्छा अभ्यास है जब एक कदम निर्माता को लागू करने बुलाया जाएगा। इसलिए जैसा ...std :: चाल असाइनमेंट ऑपरेटर के अंदर कदम

//Move constructor 
Car::Car(Car && obj) 
    : 
    prBufferLength(std::move(obj.prBufferLength)), 
    prBuffer(std::move(obj.prBuffer)) 
{ 
    obj.prBuffer = nullptr; 
    obj.prBufferLength = 0; 
} 
हालांकि सभी नमूना चाल काम ऑपरेटरों मैंने देखा है में

, वहाँ std :: एक ही कारण के लिए कदम का उपयोग करने का कोई जिक्र नहीं किया गया है। यदि सदस्य एक वस्तु है तो std :: move का उपयोग किया जाना चाहिए? इसलिए जैसा ...

//Move assignment 
Car Car::operator=(Car && obj) 
{ 
    delete[] prBuffer; 

    prBufferLength = std::move(obj.prBufferLength); 
    prBuffer = std::move(obj.prBuffer); 

    obj.prBuffer = nullptr; 
    obj.prBufferLength = 0; 
    return *this; 
} 

अद्यतन:

मैं सराहना उदाहरण मैं चुना है में std :: चाल का उपयोग करने की आवश्यकता नहीं है (खराब) लेकिन मैं सदस्यों यदि में दिलचस्पी रखता हूँ वस्तुएं थीं

+0

मुझे इस बिंदु पर कुछ स्पष्टीकरण में निश्चित रूप से रूचि है। – goji

+1

'मैंने एक और प्रश्न में पढ़ा', क्या आप उस सवाल को जोड़ सकते हैं? आपके उदाहरण में 'std :: move' का उपयोग करने का कोई कारण नहीं है। –

+0

@JesseGood संपादित देखें, धन्यवाद – TomP89

उत्तर

3

लिंक किए गए प्रश्न को पढ़ने के बाद, मैं दूसरे सबसे ऊपर दिए गए उत्तर में सलाह देख सकता हूं कि चालक कन्स्ट्रक्टर के लिए प्रारंभकर्ता सूची में std::move का उपयोग करना है क्योंकि इससे कोई फर्क नहीं पड़ता कि यह एक आदिम प्रकार है या नहीं, यह करेगा सही बात।मैं कुछ हद तक उस के साथ सहमत नहीं हैं और लगता है कि आप केवल std::move बुलाना चाहिए जहां उपयुक्त हो, लेकिन यह व्यक्तिगत वरीयताओं में आते थे।

इसके अलावा, अपनी चाल असाइनमेंट ऑपरेटर, जिस तरह से आप यह ठीक है, हालांकि मुझे लगता है कि करने के लिए अनावश्यक कॉल के लिए std::move व्यक्तिगत रूप से हटा दिया जाना चाहिए। एक और विकल्प std::swap का उपयोग करना है जो आपके लिए सही काम करेगा।

Car Car::operator=(Car && obj) 
{ 
    std::swap(this->prBufferLength, obj.prBufferLength); 
    std::swap(this->prBuffer, obj.prBuffer); 
    return *this; 
} 

ऊपर कदम असाइनमेंट ऑपरेटर और अपनी चाल असाइनमेंट ऑपरेटर के बीच का अंतर स्मृति का आवंटन रद्द करने देरी जबकि अपने संस्करण स्मृति deallocates अभी, इस कुछ स्थितियों में महत्वपूर्ण हो सकता है है।

+1

'स्वैप' _not_ सही चीज़ नहीं करेगा - स्थानांतरित वस्तु से संभावित रूप से यहां बहुत भारी है, जो कम से कम आश्चर्य के सिद्धांत का उल्लंघन करता है। – ildjarn

+0

@ildjarn: दिलचस्प बिंदु। हालांकि, चूंकि यह कहा गया है कि ऑब्जेक्ट से स्थानांतरित होने के लिए "मान्य लेकिन अनिर्दिष्ट स्थिति" है, मुझे नहीं लगता कि यह कम से कम आश्चर्य के सिद्धांत का उल्लंघन करता है। –

+0

मुझे निश्चित रूप से यह आश्चर्यजनक लगेगा कि मानक अभ्यास के मामले में मानक कंटेनर ऑब्जेक्ट्स की तत्कालियां खाली नहीं हो गईं। यानी, आमतौर पर, मैं इस कथन को मानक के परिप्रेक्ष्य से नहीं बना रहा हूं, लेकिन स्थापित अभ्यास (मेह) के परिप्रेक्ष्य से। – ildjarn

1

ऐसा लगता है कि prBuffer की तरह एक सूचक है और prBufferLength अभिन्न प्रकार किसी तरह का है, इसलिए move इस विशेष मामले में कोई फर्क के रूप में वे दोनों मौलिक प्रकार के होते हैं नहीं जा रहा है।

हैं prBuffer उदाहरण के लिए एक std::string था, तो आप move का उपयोग करना चाहिए एक कदम निर्माता का उपयोग कराने के या असाइनमेंट ऑपरेटर स्थानांतरित करने के लिए।

+0

हां, मुझे इस सवाल में उल्लेख किया जाना चाहिए था कि मैं वर्तमान में मौलिक प्रकार का उपयोग कर रहा था, स्पष्टीकरण – TomP89

1

सी ++ और जीवन में बहुत सी चीजों की तरह प्रश्न के लिए एक निश्चित हां या कोई जवाब नहीं है।

कि एक सामान्य नियम के रूप में कहा, अगर भेजे सदस्य साफ कर दिया जाएगा/रीसेट/खाली कर दिया और गंतव्य सदस्य एक असाइनमेंट ऑपरेटर का परिणाम देगा के लिए भेजे सदस्य बताए बुलाया जा रहा है, तो आप एसटीडी उपयोग करने के लिए :: तो ले जाना चाहते हैं जाएगा कि कॉपी असाइनमेंट ऑपरेटर को कॉपी असाइनमेंट ऑपरेटर के बजाय बुलाया जाएगा।

एक असाइनमेंट ऑपरेटर बुलाया नहीं किया जाएगा (अर्थात सिर्फ एक उथले नकल किया जाएगा) तो का उपयोग कर std :: कदम आवश्यक नहीं है।

0

मेरा मानना ​​है कि चालन असाइनमेंट को कार्यान्वित करने के लिए एक बेहतर तरीका है, एक नया अस्थायी ऑब्जेक्ट बनाने के लिए चालक कन्स्ट्रक्टर का उपयोग करना है, और फिर इसे प्रतिलिपि के साथ ही वर्तमान ऑब्जेक्ट के साथ स्वैप करें।

यह न केवल कोड डुप्लिकेशन से बचाता है बल्कि आपको गलती से गलतियों को रोकने से रोकता है। एक सदस्य को स्थानांतरित करने के लिए भूलना।

+0

के लिए धन्यवाद कॉपी और स्वैप कॉपी कन्स्ट्रक्टर को लागू करने का तरीका है। चालक कन्स्ट्रक्टर को बस स्वैप करना चाहिए, कोई अस्थायी आवश्यकता नहीं है। –

+0

@MooingDuck: ग्रेट प्वाइंट, मुझे यह कहने से पहले दो बार सोचना चाहिए था! – Mehrdad

+0

एआरएम, @ म्यूइंग डक, कॉपी कॉपी को लागू करने के लिए आप कॉपी और कुछ भी कैसे उपयोग करते हैं? प्रतिलिपि क्या है? मुझे लगता है कि आपका मतलब कॉपी और स्वैप कॉपी _assignment_ को लागू करने का एक अच्छा तरीका है, जो मेहरदद ने पहले स्थान पर कहा था, साथ ही चाल असाइनमेंट के बारे में बात करने के साथ-साथ एक चालक कन्स्ट्रक्टर भी नहीं था। –

1

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

Car Car::operator=(Car && obj) 
{ 
    // don't need this, it will be handled by obj's destructor 
    // delete[] prBuffer; 

    using std::swap; 
    swap(prBuffer, obj.prBuffer); 
    swap(prBufferLength, obj.prBufferLength); 

    return *this; 
} 

इसके अलावा Copy-and-Swap मुहावरा पर एक नज़र डालें। जो आपको एक ही असाइनमेंट ऑपरेटर का उपयोग दोनों चाल और प्रतिलिपि के लिए करने की अनुमति देता है, लेकिन थोड़ी सी कमी है कि स्व-असाइनमेंट परिणाम अनावश्यक प्रतिलिपि में होता है।

+0

असल में, ऑब्जेक्ट के विनाशक का जिक्र करते हुए सुझाव दिया गया है कि यह एक बहुत अच्छा विचार नहीं है। यदि 'obj' एक लवल्यू होता है जिसे स्पष्ट रूप से स्थानांतरित किया जा रहा है, तो यह कॉल के बाद मौजूद रहेगा। इससे सूक्ष्म समस्याएं हो सकती हैं, उदा। यदि 'prBuffer' उन ऑब्जेक्ट्स को इंगित करता है जिनके पास कुछ संसाधनों के लिए विशेष पहुंच है। –