हमें कॉपी कंस्ट्रक्टर का उपयोग कब करना है?


87

मुझे पता है कि C ++ कंपाइलर एक क्लास के लिए कॉपी कंस्ट्रक्टर बनाता है। हमें किस मामले में उपयोगकर्ता द्वारा परिभाषित कॉपी कंस्ट्रक्टर लिखना होगा? क्या आप कुछ उदाहरण दे सकते हैं?



1
अपनी खुद की कॉपी-कोटर लिखने के मामलों में से एक: जब आपको गहरी कॉपी करनी होगी। यह भी ध्यान दें कि जैसे ही आप एक ctor बनाते हैं, आपके लिए कोई डिफ़ॉल्ट ctor नहीं बनाया जाता है (जब तक आप डिफ़ॉल्ट कीवर्ड का उपयोग नहीं करते हैं)।

जवाबों:


75

कंपाइलर द्वारा बनाई गई कॉपी कंस्ट्रक्टर सदस्य वार कॉपीिंग करता है। कभी-कभी यह पर्याप्त नहीं होता है। उदाहरण के लिए:

class Class {
public:
    Class( const char* str );
    ~Class();
private:
    char* stored;
};

Class::Class( const char* str )
{
    stored = new char[srtlen( str ) + 1 ];
    strcpy( stored, str );
}

Class::~Class()
{
    delete[] stored;
}

इस मामले में सदस्य-वार कॉपी कॉपी storedकरने वाले बफर की नकल नहीं करेंगे (केवल पॉइंटर को कॉपी किया जाएगा), इसलिए बफर को साझा करने वाली कॉपी को नष्ट करने वाली पहली कॉल delete[]सफलतापूर्वक होगी और दूसरी अपरिभाषित व्यवहार में चलेगी। आपको गहरी कॉपी कॉपी निर्माता (और असाइनमेंट ऑपरेटर के रूप में अच्छी तरह से) की आवश्यकता है।

Class::Class( const Class& another )
{
    stored = new char[strlen(another.stored) + 1];
    strcpy( stored, another.stored );
}

void Class::operator = ( const Class& another )
{
    char* temp = new char[strlen(another.stored) + 1];
    strcpy( temp, another.stored);
    delete[] stored;
    stored = temp;
}

10
यह बिट-वार प्रदर्शन नहीं करता है, लेकिन सदस्य-वार कॉपी जो विशेष रूप से क्लास-टाइप सदस्यों के लिए कॉपी-कॉटर को आमंत्रित करता है।
जॉर्ज फ्रिट्ज़शे

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

@ नीचे से तीसरी पंक्ति आपके पास है delete stored[];और मेरा मानना ​​है कि यह होना चाहिएdelete [] stored;
पीटर अज़ताई

4
मुझे पता है कि यह सिर्फ एक उदाहरण है, लेकिन आपको बेहतर समाधान का उपयोग करना चाहिए std::string। सामान्य विचार यह है कि केवल उपयोगिता वर्ग जो संसाधनों का प्रबंधन करते हैं उन्हें बिग थ्री को अधिभारित करने की आवश्यकता होती है, और अन्य सभी वर्गों को केवल उन उपयोगिता वर्गों का उपयोग करना चाहिए, जिससे बिग थ्री में से किसी को परिभाषित करने की आवश्यकता न हो।
GManNickG

2
@ मर्टिन: मैं यह सुनिश्चित करना चाहता था कि यह पत्थर में खुदी हुई हो। : P
GManNickG

46

मैं थोड़ा हैरान हूं कि नियम का Rule of Fiveहवाला नहीं दिया गया।

यह नियम बहुत सरल है:

पांच का नियम :
जब भी आप डिस्ट्रक्टर, कॉपी कंस्ट्रक्टर, कॉपी असाइनमेंट ऑपरेटर, मूव कंस्ट्रक्टर या मूव असाइनमेंट ऑपरेटर में से किसी एक को लिख रहे होते हैं, तो आपको संभवतः अन्य चार लिखने की आवश्यकता होती है।

लेकिन एक और सामान्य दिशानिर्देश है जिसका आपको पालन करना चाहिए, जो अपवाद-सुरक्षित कोड लिखने की आवश्यकता से उत्पन्न होता है:

प्रत्येक संसाधन को एक समर्पित वस्तु द्वारा प्रबंधित किया जाना चाहिए

यहाँ @sharptoothकोड अभी भी (ज्यादातर) ठीक है, हालांकि अगर वह अपनी कक्षा में दूसरी विशेषता जोड़ते हैं तो यह नहीं होगा। निम्नलिखित वर्ग पर विचार करें:

class Erroneous
{
public:
  Erroneous();
  // ... others
private:
  Foo* mFoo;
  Bar* mBar;
};

Erroneous::Erroneous(): mFoo(new Foo()), mBar(new Bar()) {}

अगर new Barफेंकता है तो क्या होता है? आप द्वारा बताई गई वस्तु को कैसे हटाते हैं mFoo? वहाँ समाधान कर रहे हैं (कार्य स्तर की कोशिश / पकड़ ...), वे सिर्फ पैमाने नहीं है।

स्थिति से निपटने का उचित तरीका कच्चे पॉइंटर्स के बजाय उचित वर्गों का उपयोग करना है।

class Righteous
{
public:
private:
  std::unique_ptr<Foo> mFoo;
  std::unique_ptr<Bar> mBar;
};

एक ही निर्माता के कार्यान्वयन के साथ (या वास्तव में, उपयोग करते हुए make_unique), मेरे पास अब मुफ्त में अपवाद सुरक्षा है !!! क्या यह रोमांचक नहीं है? और सबसे अच्छा, मुझे अब उचित विध्वंसक के बारे में चिंता करने की आवश्यकता नहीं है! मुझे अपना Copy Constructorऔर Assignment Operatorहालांकि लिखने की ज़रूरत है , क्योंकि unique_ptrइन ऑपरेशनों को परिभाषित नहीं करता है ... लेकिन यहां कोई फर्क नहीं पड़ता;)

और इसलिए, sharptoothवर्ग का पुनरीक्षण किया गया:

class Class
{
public:
  Class(char const* str): mData(str) {}
private:
  std::string mData;
};

मैं आपके बारे में नहीं जानता, लेकिन मुझे मेरा काम आसान लगता है;)


सी ++ 11 के लिए - पांच का नियम जो तीन मूव कंस्ट्रक्टर और मूव असाइनमेंट ऑपरेटर के नियम को जोड़ता है।
रॉबर्ट एंड्रीजुक

1
@ रब: ध्यान दें कि वास्तव में, जैसा कि पिछले उदाहरण में दिखाया गया है, आपको आम तौर पर शून्य के नियम के लिए लक्ष्य बनाना चाहिए । केवल विशेष (सामान्य) तकनीकी वर्गों को एक संसाधन को संभालने के बारे में ध्यान देना चाहिए , अन्य सभी वर्गों को उन स्मार्ट पॉइंटर्स / कंटेनरों का उपयोग करना चाहिए और इसके बारे में चिंता नहीं करनी चाहिए।
मैथ्यू एम।

@MatthieuM। सहमत :-) मैंने पांच के नियम का उल्लेख किया है, क्योंकि यह उत्तर C ++ 11 से पहले है और "बिग थ्री" से शुरू होता है, लेकिन यह उल्लेख किया जाना चाहिए कि अब "बिग फाइव" प्रासंगिक हैं। मैं इस जवाब को वोट नहीं देना चाहता क्योंकि यह पूछे गए संदर्भ में सही है।
रॉबर्ट एंड्रीजुक

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

32

मैं अपने अभ्यास से याद कर सकता हूं और निम्नलिखित मामलों के बारे में सोच सकता हूं जब किसी को कॉपी कंस्ट्रक्टर को स्पष्ट रूप से घोषित / परिभाषित करने से निपटना होगा। मैंने मामलों को दो श्रेणियों में बांटा है

  • सुधार / शब्दार्थ - यदि आप उपयोगकर्ता-परिभाषित कॉपी-कंस्ट्रक्टर प्रदान नहीं करते हैं, तो उस प्रकार का उपयोग करने वाले प्रोग्राम संकलन करने में विफल हो सकते हैं, या गलत तरीके से काम कर सकते हैं।
  • ऑप्टिमाइज़ेशन - कंपाइलर-जनरेट किए गए कॉपी कंस्ट्रक्टर को एक अच्छा विकल्प प्रदान करने से प्रोग्राम को तेज़ बनाने की अनुमति मिलती है।


शुद्धता / शब्दार्थ

मैं इस भाग में उन मामलों को रखता हूँ जहाँ कॉपी कंस्ट्रक्टर को घोषित / परिभाषित करना, उस प्रकार का उपयोग करके कार्यक्रमों के सही संचालन के लिए आवश्यक है।

इस खंड के माध्यम से पढ़ने के बाद, आप कंपाइलर को अपने आप कॉपी कॉपी बनाने की अनुमति देने के कई नुकसानों के बारे में जानेंगे। इसलिए, के रूप में seand उसकी में बताया गया है इस सवाल का जवाब है, यह हमेशा सुरक्षित एक नया वर्ग के लिए copyability बंद कर देते हैं और करने के लिए है जानबूझ कर बाद में जब वास्तव में जरूरत है इसे सक्षम करें।

C ++ 03 में एक वर्ग को गैर-प्रतिलिपि कैसे बनाया जाए

एक निजी कॉपी-कंस्ट्रक्टर की घोषणा करें और इसके लिए कार्यान्वयन प्रदान न करें (ताकि बिल्ड लिंकिंग स्टेज पर विफल हो जाए, भले ही उस प्रकार की वस्तुओं को क्लास के अपने दायरे में या उसके दोस्तों द्वारा कॉपी किया गया हो)।

C ++ 11 या नए में एक वर्ग को गैर-प्रतिलिपि कैसे बनाया जाए

कॉपी-कंस्ट्रक्टर =deleteको अंत में घोषित करें ।


शॉल बनाम डीप कॉपी

यह सबसे अच्छा समझा जाने वाला मामला है और वास्तव में अन्य उत्तरों में वर्णित एकमात्र है। shaprtooth ने इसे बहुत अच्छी तरह से कवर किया है। मैं केवल उस गहराई से कॉपी करने वाले संसाधनों को जोड़ना चाहता हूं जो विशेष रूप से ऑब्जेक्ट के स्वामित्व में होना चाहिए, किसी भी प्रकार के संसाधनों पर लागू हो सकता है, जिनमें से गतिशील रूप से आवंटित स्मृति केवल एक प्रकार है। जरूरत पड़ने पर किसी वस्तु की गहराई से नकल करने की भी आवश्यकता हो सकती है

  • डिस्क पर अस्थायी फ़ाइलों की प्रतिलिपि बनाना
  • एक अलग नेटवर्क कनेक्शन खोलना
  • एक अलग कार्यकर्ता धागा बनाना
  • एक अलग OpenGL फ्रेमबफ़र आवंटित
  • आदि

स्व-पंजीकृत वस्तुओं

एक वर्ग पर विचार करें जहां सभी वस्तुओं - चाहे वे कैसे भी बनाए गए हों - किसी भी तरह पंजीकृत होना चाहिए। कुछ उदाहरण:

  • सबसे सरल उदाहरण: वर्तमान में मौजूद वस्तुओं की कुल संख्या को बनाए रखना। ऑब्जेक्ट पंजीकरण केवल स्थैतिक काउंटर को बढ़ाने के बारे में है।

  • एक अधिक जटिल उदाहरण एक सिंगलटन रजिस्ट्री है, जहां उस प्रकार की सभी मौजूदा वस्तुओं के संदर्भ संग्रहीत किए जाते हैं (ताकि उन सभी को सूचनाएं पहुंचाई जा सकें)।

  • गिने हुए स्मार्ट-पॉइंटर्स को इस श्रेणी में केवल एक विशेष मामला माना जा सकता है: नया पॉइंटर वैश्विक रजिस्ट्री के बजाय साझा संसाधन के साथ "रजिस्टर" करता है।

इस तरह के स्व-पंजीकरण ऑपरेशन को किसी भी प्रकार के निर्माता द्वारा किया जाना चाहिए और कॉपी कंस्ट्रक्टर अपवाद नहीं है।


आंतरिक क्रॉस-रेफरेंस वाली वस्तुएँ

कुछ वस्तुओं में गैर-तुच्छ आंतरिक संरचना हो सकती है, जो उनके अलग-अलग उप-वस्तुओं के बीच प्रत्यक्ष क्रॉस-रेफरेंस के साथ होती है (वास्तव में, इस मामले को ट्रिगर करने के लिए बस एक ऐसा आंतरिक क्रॉस-रेफरेंस पर्याप्त है)। संकलक-प्रदान की प्रतिलिपि निर्माता आंतरिक टूट जाएगा इंट्रा-वस्तु संघों, उन्हें परिवर्तित अंतर-वस्तु संघों।

एक उदाहरण:

struct MarriedMan;
struct MarriedWoman;

struct MarriedMan {
    // ...
    MarriedWoman* wife;   // association
};

struct MarriedWoman {
    // ...
    MarriedMan* husband;  // association
};

struct MarriedCouple {
    MarriedWoman wife;    // aggregation
    MarriedMan   husband; // aggregation

    MarriedCouple() {
        wife.husband = &husband;
        husband.wife = &wife;
    }
};

MarriedCouple couple1; // couple1.wife and couple1.husband are spouses

MarriedCouple couple2(couple1);
// Are couple2.wife and couple2.husband indeed spouses?
// Why does couple2.wife say that she is married to couple1.husband?
// Why does couple2.husband say that he is married to couple1.wife?

केवल कुछ मानदंडों को पूरा करने वाली वस्तुओं को कॉपी करने की अनुमति है

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


गैर-प्रतिलिपि योग्य उप-ऑब्जेक्ट

कभी-कभी, एक वर्ग जो प्रतिलिपि योग्य होना चाहिए, वह गैर-प्रतिलिपि योग्य उप-ऑब्जेक्ट को एकत्र करता है। आमतौर पर, यह गैर-पर्यवेक्षित राज्य वाली वस्तुओं के लिए होता है (उस मामले को "अनुकूलन" अनुभाग में और अधिक विस्तार से चर्चा की गई है)। संकलक केवल उस मामले को पहचानने में मदद करता है।


अर्ध-प्रतिलिपि योग्य उप-वस्तुएँ

एक वर्ग, जो प्रतिलिपि योग्य होना चाहिए, एक अर्ध-प्रतिलिपि योग्य प्रकार के उप-ऑब्जेक्ट को एकत्रित कर सकता है। एक अर्ध-प्रतिलिपि योग्य प्रकार सख्त अर्थ में एक प्रतिलिपि निर्माता प्रदान नहीं करता है, लेकिन एक अन्य निर्माता है जो ऑब्जेक्ट की एक वैचारिक प्रतिलिपि बनाने की अनुमति देता है। एक प्रकार के अर्ध-प्रतिलिपि बनाने का कारण यह है कि जब प्रकार के प्रतिलिपि शब्दार्थ के बारे में कोई पूर्ण सहमति नहीं है।

उदाहरण के लिए, ऑब्जेक्ट सेल्फ-रजिस्ट्रेशन मामले पर दोबारा गौर करते हुए, हम यह तर्क दे सकते हैं कि ऐसी परिस्थितियाँ हो सकती हैं, जहाँ किसी ऑब्जेक्ट को वैश्विक ऑब्जेक्ट मैनेजर के साथ पंजीकृत होना चाहिए, अगर यह एक पूर्ण स्टैंडअलोन ऑब्जेक्ट है। यदि यह किसी अन्य वस्तु का उप-उद्देश्य है, तो इसे प्रबंधित करने की जिम्मेदारी इसकी युक्त वस्तु के साथ है।

या, उथले और गहरी नकल दोनों का समर्थन किया जाना चाहिए (उनमें से कोई भी डिफ़ॉल्ट नहीं है)।

फिर अंतिम निर्णय उस प्रकार के उपयोगकर्ताओं के लिए छोड़ दिया जाता है - जब वस्तुओं की प्रतिलिपि बनाते हैं, तो उन्हें प्रतिलिपि के इच्छित तरीके को स्पष्ट रूप से निर्दिष्ट करना होगा (अतिरिक्त तर्कों के माध्यम से)।

प्रोग्रामिंग के लिए एक गैर-रक्षात्मक दृष्टिकोण के मामले में, यह भी संभव है कि एक नियमित प्रतिलिपि-निर्माता और अर्ध-प्रतिलिपि-निर्माता दोनों मौजूद हों। यह उचित हो सकता है जब अधिकांश मामलों में एक ही नकल पद्धति लागू की जानी चाहिए, जबकि दुर्लभ लेकिन अच्छी तरह से समझी जाने वाली स्थितियों में वैकल्पिक नकल विधियों का उपयोग किया जाना चाहिए। तब कंपाइलर शिकायत नहीं करेगा कि यह कॉपी कंस्ट्रक्टर को स्पष्ट रूप से परिभाषित करने में असमर्थ है; यह याद रखना और जाँचना उपयोगकर्ताओं की पूरी ज़िम्मेदारी होगी कि उस प्रकार के उप-ऑब्जेक्ट को अर्ध-प्रतिलिपि-निर्माता के माध्यम से कॉपी किया जाए या नहीं।


उस राज्य की प्रतिलिपि न करें जो वस्तु की पहचान के साथ दृढ़ता से जुड़ा हो

दुर्लभ मामलों में ऑब्जेक्ट की अवलोकनीय स्थिति का एक सबसेट वस्तु की पहचान का एक अविभाज्य हिस्सा बन सकता है (या माना जाता है) अन्य वस्तुओं के लिए हस्तांतरणीय नहीं होना चाहिए (हालांकि यह कुछ विवादास्पद हो सकता है)।

उदाहरण:

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

  • वस्तु का इतिहास (जैसे कि पूर्ववत करें / फिर से करें) मामले में जब नई वस्तु को स्रोत वस्तु का इतिहास विरासत में नहीं मिलना चाहिए, लेकिन इसके बजाय एक एकल इतिहास आइटम " <TIME> पर <OTHER_OBJECTYID> से कॉपी किया गया " से शुरू करें।

ऐसे मामलों में कॉपी कंस्ट्रक्टर को संबंधित उप-ऑब्जेक्ट को कॉपी करना छोड़ देना चाहिए।


प्रतिलिपि निर्माता के सही हस्ताक्षर लागू करना

कंपाइलर-प्रदत्त कॉपी कंस्ट्रक्टर का हस्ताक्षर इस बात पर निर्भर करता है कि सब-ऑब्जेक्ट्स के लिए कौन से कॉपी कंस्ट्रक्टर उपलब्ध हैं। यदि कम से कम एक उप-ऑब्जेक्ट में वास्तविक कॉपी कंस्ट्रक्टर नहीं है (स्रोत ऑब्जेक्ट को लगातार संदर्भ द्वारा ले रहा है), लेकिन इसके बजाय एक म्यूटिंग कॉपी-कंस्ट्रक्टर (गैर-निरंतर संदर्भ द्वारा स्रोत ऑब्जेक्ट ले रहा है) तो कंपाइलर के पास कोई विकल्प नहीं होगा लेकिन स्पष्ट रूप से घोषित करने और फिर एक म्यूटिंग कॉपी-कंस्ट्रक्टर को परिभाषित करने के लिए।

अब, क्या होगा अगर उप-ऑब्जेक्ट के प्रकार के "म्यूटिंग" कॉपी-निर्माता वास्तव में स्रोत ऑब्जेक्ट को म्यूट नहीं करता है (और बस एक प्रोग्रामर द्वारा लिखा गया था जो constकीवर्ड के बारे में नहीं जानता है )? यदि हमारे पास उस कोड को लापता जोड़कर तय नहीं किया जा सकता है const, तो दूसरा विकल्प हमारे अपने उपयोगकर्ता-परिभाषित कॉपी कंस्ट्रक्टर को एक सही हस्ताक्षर के साथ घोषित करने और पाप को मोड़ने का पाप करना है const_cast


कॉपी-ऑन-राइट (गाय)

एक गाय का कंटेनर जिसने अपने आंतरिक डेटा को प्रत्यक्ष संदर्भ दिया है, उसे निर्माण के समय गहराई से कॉपी किया जाना चाहिए, अन्यथा यह एक संदर्भ गिनती संभाल के रूप में व्यवहार कर सकता है।

हालांकि, गाय एक अनुकूलन तकनीक है, कॉपी कन्स्ट्रक्टर में यह तर्क इसके सही कार्यान्वयन के लिए महत्वपूर्ण है। यही कारण है कि मैंने इस मामले को "अनुकूलन" अनुभाग के बजाय यहां रखा, जहां हम अगले जाते हैं।



अनुकूलन

निम्नलिखित मामलों में आप अपनी खुद की कॉपी कंस्ट्रक्टर को ऑप्टिमाइज़ेशन चिंताओं से बाहर निकाल सकते हैं।


कॉपी के दौरान संरचना अनुकूलन

एक कंटेनर पर विचार करें जो तत्व हटाने के संचालन का समर्थन करता है, लेकिन हटाए गए तत्व को बस चिह्नित करके ऐसा कर सकता है, और बाद में इसके स्लॉट को रीसायकल कर सकता है। जब इस तरह के कंटेनर की एक प्रतिलिपि बनाई जाती है, तो यह "हटाए गए" स्लॉट को संरक्षित करने के बजाय जीवित डेटा को कॉम्पैक्ट करने के लिए समझ में आता है।


गैर-अवलोकन योग्य राज्य की नकल करना छोड़ दें

किसी ऑब्जेक्ट में डेटा हो सकता है जो उसकी अवलोकन अवस्था का हिस्सा नहीं है। आमतौर पर, यह ऑब्जेक्ट के जीवनकाल के दौरान संचित डेटा को कुछ धीमी गति से संचालित क्वेरी संचालन को गति देने के लिए संचित / याद किया जाता है। उस डेटा को कॉपी करना छोड़ देना सुरक्षित है, क्योंकि यह प्रासंगिक संचालन किए जाने पर (और यदि!) पुनर्गणना हो जाएगा। इस डेटा को कॉपी करना अनुचित हो सकता है, क्योंकि यह जल्दी से अमान्य हो सकता है यदि ऑब्जेक्ट के अवलोकन योग्य स्थिति (जिसमें से कैश्ड डेटा प्राप्त होता है) को म्यूटेशन परिचालनों द्वारा संशोधित किया जाता है (और यदि हम ऑब्जेक्ट को संशोधित नहीं करने जा रहे हैं, तो हम एक गहरी स्थिति क्यों बना रहे हैं? तब कॉपी?)

यह अनुकूलन केवल तभी उचित है जब अवलोकन योग्य स्थिति का प्रतिनिधित्व करने वाले डेटा की तुलना में सहायक डेटा बड़ा हो।


अंतर्निहित प्रतिलिपि अक्षम करें

C ++ कॉपी कंस्ट्रक्टर घोषित करके अंतर्निहित प्रतिलिपि को अक्षम करने की अनुमति देता है explicit। तब उस वर्ग की वस्तुओं को कार्यों में पारित नहीं किया जा सकता है और / या मान से कार्यों से लौटा दिया जाता है। इस ट्रिक का उपयोग एक ऐसे प्रकार के लिए किया जा सकता है जो हल्का प्रतीत होता है लेकिन वास्तव में कॉपी करना बहुत महंगा है (हालांकि, इसे क्वैसी-कॉपी करने योग्य बेहतर विकल्प हो सकता है)।

C ++ 03 में एक कॉपी कंस्ट्रक्टर की घोषणा करते हुए इसे परिभाषित करने की आवश्यकता है (निश्चित रूप से, यदि आप इसका उपयोग करना चाहते हैं)। इसलिए, इस तरह के एक कॉपी कंस्ट्रक्टर के लिए जा रही चिंता से बाहर केवल चर्चा का मतलब है कि आपको एक ही कोड लिखना होगा जो कंपाइलर आपके लिए स्वचालित रूप से उत्पन्न करेगा।

C ++ 11 और नए मानक विशेष सदस्य फ़ंक्शंस (डिफ़ॉल्ट और कॉपी कंस्ट्रक्टर, कॉपी-असाइनमेंट ऑपरेटर, और डिस्ट्रक्टर) को स्पष्ट कार्यान्वयन के साथ डिफ़ॉल्ट कार्यान्वयन का उपयोग करने की अनुमति देते हैं (बस घोषणा को समाप्त करें =default)।



Todos

इस उत्तर को इस प्रकार सुधारा जा सकता है:

  • अधिक उदाहरण कोड जोड़ें
  • "आंतरिक क्रॉस-रेफरेंस वाले ऑब्जेक्ट" मामले का चित्रण करें
  • कुछ लिंक जोड़ें

6

यदि आपके पास एक वर्ग है जिसने गतिशील रूप से सामग्री आवंटित की है। उदाहरण के लिए आप एक पुस्तक का शीर्षक चार * के रूप में संग्रहीत करते हैं और शीर्षक को नए के साथ सेट करते हैं, प्रतिलिपि काम नहीं करेगी।

आपको एक कॉपी कंस्ट्रक्टर लिखना होगा जो करता है title = new char[length+1]और फिर strcpy(title, titleIn)। कॉपी कंस्ट्रक्टर सिर्फ एक "उथला" कॉपी करेगा।


2

कॉपी कन्स्ट्रक्टर को उस समय कहा जाता है जब कोई ऑब्जेक्ट या तो वैल्यू द्वारा पास किया जाता है, वैल्यू द्वारा लौटाया जाता है या स्पष्ट रूप से कॉपी किया जाता है। यदि कोई कॉपी कंस्ट्रक्टर नहीं है, तो c ++ एक डिफॉल्ट कॉपी कंस्ट्रक्टर बनाता है जो उथली प्रति बनाता है। यदि ऑब्जेक्ट में डायनामिक रूप से आवंटित मेमोरी के लिए कोई पॉइंटर्स नहीं है, तो उथला कॉपी करेगा।


0

जब तक वर्ग को विशेष रूप से इसकी आवश्यकता न हो, तब तक प्रतिलिपि ctor, और ऑपरेटर = को अक्षम करना अक्सर एक अच्छा विचार होता है। यह अक्षमता को रोक सकता है जैसे संदर्भ के उद्देश्य से मूल्य द्वारा एक arg पास करना। इसके अलावा संकलक उत्पन्न तरीके अमान्य हो सकते हैं।


-1

आइए नीचे कोड स्निपेट पर विचार करें:

class base{
    int a, *p;
public:
    base(){
        p = new int;
    }
    void SetData(int, int);
    void ShowData();
    base(const base& old_ref){
        //No coding present.
    }
};
void base :: ShowData(){
    cout<<this->a<<" "<<*(this->p)<<endl;
}
void base :: SetData(int a, int b){
    this->a = a;
    *(this->p) = b;
}
int main(void)
{
    base b1;
    b1.SetData(2, 3);
    b1.ShowData();
    base b2 = b1; //!! Copy constructor called.
    b2.ShowData();
    return 0;
}

Output: 
2 3 //b1.ShowData();
1996774332 1205913761 //b2.ShowData();

b2.ShowData();जंक आउटपुट देता है क्योंकि स्पष्ट रूप से डेटा की प्रतिलिपि करने के लिए कोई कोड नहीं लिखा गया है जिसके साथ एक उपयोगकर्ता-परिभाषित कॉपी-कंस्ट्रक्टर है। इसलिए कंपाइलर समान नहीं बनाता है।

बस इस ज्ञान को आप सभी के साथ साझा करने के बारे में सोचा, हालाँकि आप में से अधिकांश इसे पहले से ही जानते हैं।

चीयर्स ... हैप्पी कोडिंग !!!

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