2012-10-29 12 views
16

मैं उलझन में हूं जब एक चालक कन्स्ट्रक्टर को कॉपी कॉपी कन्स्ट्रक्टर कहा जाता है। मैं पढ़ा है निम्न स्रोतों:कन्स्ट्रक्टर को कब ले जाता है?

Move constructor is not getting called in C++0x

Move semantics and rvalue references in C++11

msdn

इन स्रोतों में से सभी कर रहे हैं या तो overcomplicated (मैं सिर्फ एक सरल उदाहरण चाहते हैं) या केवल कैसे एक लिखने के लिए दिखाने कन्स्ट्रक्टर को ले जाएं, लेकिन इसे कॉल करने के लिए नहीं। Ive लिखा एक साधारण सी समस्या अधिक विशिष्ट:

const class noConstruct{}NoConstruct; 
class a 
{ 
private: 
    int *Array; 
public: 
    a(); 
    a(noConstruct); 
    a(const a&); 
    a& operator=(const a&); 
    a(a&&); 
    a& operator=(a&&); 
    ~a(); 
}; 

a::a() 
{ 
    Array=new int[5]{1,2,3,4,5}; 
} 
a::a(noConstruct Parameter) 
{ 
    Array=nullptr; 
} 
a::a(const a& Old): Array(Old.Array) 
{ 

} 
a& a::operator=(const a&Old) 
{ 
    delete[] Array; 
    Array=new int[5]; 
    for (int i=0;i!=5;i++) 
    { 
     Array[i]=Old.Array[i]; 
    } 
    return *this; 
} 
a::a(a&&Old) 
{ 
    Array=Old.Array; 
    Old.Array=nullptr; 
} 
a& a::operator=(a&&Old) 
{ 
    Array=Old.Array; 
    Old.Array=nullptr; 
    return *this; 
} 
a::~a() 
{ 
    delete[] Array; 
} 

int main() 
{ 
    a A(NoConstruct),B(NoConstruct),C; 
    A=C; 
    B=C; 
} 

वर्तमान में ए, बी, और सी सभी विभिन्न सूचक मान हैं। मैं चाहता हूं कि ए को एक नया पॉइंटर होना चाहिए, बी को सी के पुराने सूचक होने के लिए, और सी को एक नल पॉइंटर होना चाहिए।

कुछ हद तक विषय बंद है, लेकिन अगर कोई दस्तावेज सुझा सकता है जहां मैं इन नई सुविधाओं के बारे में विस्तार से सीख सकता हूं तो मैं आभारी रहूंगा और शायद कई और प्रश्न पूछने की आवश्यकता नहीं होगी।

+0

एक आंशिक रूप से संबंधित मामले पर, आप प्रतिलिपि जाँच करना चाहते हैं और अपने assignement के लिए स्वैप मुहावरा http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom सकता है ऑपरेटर। – undu

+0

[संबंधित एफएक्यू] (http: // stackoverflow।कॉम/प्रश्न/3106110 /) – fredoverflow

उत्तर

22

एक कदम निर्माता कहा जाता है:

  • एक ऑब्जेक्ट प्रारंभकर्ता std::move(something)
  • है जब एक ऑब्जेक्ट प्रारंभकर्ता std::forward<T>(something) है और T एक lvalue संदर्भ प्रकार ("आदर्श के लिए टेम्पलेट प्रोग्रामिंग में उपयोगी नहीं है जब अग्रेषण ")
  • जब कोई ऑब्जेक्ट प्रारंभकर्ता अस्थायी होता है और संकलक प्रतिलिपि/चाल पूरी तरह से
  • को समाप्त नहीं करता है 10
  • जब मूल्य द्वारा एक समारोह स्थानीय वर्ग वस्तु लौटने और संकलक प्रतिलिपि को समाप्त नहीं करती/ले जाने के लिए पूरी तरह से
  • जब एक समारोह स्थानीय वर्ग वस्तु फेंक और संकलक प्रतिलिपि समाप्त नहीं करती है/पूरी तरह से ले जाने के

यह एक पूरी सूची नहीं है। ध्यान दें कि पैरामीटर में क्लास प्रकार (संदर्भ नहीं) है, तो "ऑब्जेक्ट प्रारंभकर्ता" फ़ंक्शन तर्क हो सकता है।

a RetByValue() { 
    a obj; 
    return obj; // Might call move ctor, or no ctor. 
} 

void TakeByValue(a); 

int main() { 
    a a1; 
    a a2 = a1; // copy ctor 
    a a3 = std::move(a1); // move ctor 

    TakeByValue(std::move(a2)); // Might call move ctor, or no ctor. 

    a a4 = RetByValue(); // Might call move ctor, or no ctor. 

    a1 = RetByValue(); // Calls move assignment, a::operator=(a&&) 
} 
4

सबसे पहले, आपकी प्रतिलिपि निर्माता टूट गया है। ऑब्जेक्ट्स से प्रतिलिपि बनाई गई और प्रतिलिपि बनाई गई दोनों ही Array पर इंगित करेंगी और दोनों delete[] को स्कोप से बाहर होने पर प्रयास करेंगे, जिसके परिणामस्वरूप अपरिभाषित व्यवहार होगा। इसे ठीक करने के लिए, सरणी की प्रति बनाएं।

a::a(const a& Old): Array(new int[5]) 
{ 
    for(size_t i = 0; i < 5; ++i) { 
    Array[i] = Old.Array[i]; 
    } 
} 

अब, चाल काम के रूप में आप इसे होना चाहते हैं किया जा रहा है नहीं है, क्योंकि दोनों काम के बयानों के बजाय rvalues ​​का उपयोग कर के, lvalues ​​से बताए जाते हैं। चालों को करने के लिए, आपको एक रावल्यू से आगे बढ़ना चाहिए, या यह एक संदर्भ होना चाहिए जहां एक लाभा को एक रावल्यू (जैसे फ़ंक्शन का रिटर्न स्टेटमेंट) माना जा सकता है।

वांछित प्रभाव प्राप्त करने के लिए std::move का उपयोग एक रावल्यू संदर्भ बनाने के लिए करें।

A=C;    // A will now contain a copy of C 
B=std::move(C); // Calls the move assignment operator 
+0

'बी = एसडीडी :: चाल (सी); // कॉपी असाइनमेंट ऑपरेटर को कॉल करता है 'क्या यह चाल असाइनमेंट ऑपरेटर नहीं होना चाहिए? इसके बाद, सी अब ऐसा नहीं हो सकता है। – RainingChain

+0

@RainingChain हाँ, वह एक टाइपो था, धन्यवाद! – Praetorian

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