c++ तीन का नियम क्या है?




copy-constructor assignment-operator (7)

ऑब्जेक्ट की प्रतिलिपि बनाने का मतलब क्या है? कॉपी कन्स्ट्रक्टर और कॉपी असाइनमेंट ऑपरेटर क्या हैं? मुझे उन्हें खुद घोषित करने की आवश्यकता कब होगी? मैं अपनी वस्तुओं को कॉपी करने से कैसे रोक सकता हूं?


बड़े तीनों का कानून ऊपर निर्दिष्ट है।

एक आसान उदाहरण, सादे अंग्रेजी में, जिस तरह की समस्या हल होती है:

गैर डिफ़ॉल्ट विनाशक

आपने अपने कन्स्ट्रक्टर में मेमोरी आवंटित की है और इसलिए इसे हटाने के लिए आपको एक विनाशक लिखना होगा। अन्यथा आप एक स्मृति रिसाव का कारण बनेंगे।

आपको लगता है कि यह काम किया गया है।

समस्या होगी, अगर आपकी प्रतिलिपि एक प्रतिलिपि बनाई गई है, तो प्रतिलिपि मूल वस्तु के समान स्मृति को इंगित करेगी।

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

इसलिए, आप एक कॉपी कन्स्ट्रक्टर लिखते हैं ताकि यह नई वस्तुओं को नष्ट करने के लिए स्मृति के अपने टुकड़े आवंटित कर सके।

असाइनमेंट ऑपरेटर और कॉपी कन्स्ट्रक्टर

आपने अपने कन्स्ट्रक्टर में अपनी कक्षा के सदस्य सूचक को स्मृति आवंटित की है। जब आप इस वर्ग की किसी ऑब्जेक्ट की प्रतिलिपि बनाते हैं तो डिफ़ॉल्ट असाइनमेंट ऑपरेटर और कॉपी कन्स्ट्रक्टर इस सदस्य पॉइंटर के मान को नई ऑब्जेक्ट में कॉपी करेगा।

इसका मतलब है कि नई वस्तु और पुरानी वस्तु स्मृति के उसी टुकड़े पर इंगित करेगी, इसलिए जब आप इसे एक ऑब्जेक्ट में बदलते हैं तो यह अन्य objerct के लिए भी बदला जाएगा। यदि एक वस्तु इस स्मृति को हटा देती है तो दूसरा इसका उपयोग करने की कोशिश कर लेगा - eek।

इसे हल करने के लिए आप कॉपी कन्स्ट्रक्टर और असाइनमेंट ऑपरेटर का अपना संस्करण लिखते हैं। आपके संस्करण नई ऑब्जेक्ट्स को अलग-अलग मेमोरी आवंटित करते हैं और उन मानों की प्रतिलिपि बनाते हैं जो पहले सूचक अपने पते के बजाय इंगित कर रहे हैं।


मौजूदा उत्तरों में से कई पहले ही कॉपी कन्स्ट्रक्टर, असाइनमेंट ऑपरेटर और विनाशक को छूते हैं। हालांकि, पोस्ट सी ++ 11 में, स्थानांतरण अर्थात् परिचय की शुरुआत 3 से अधिक हो सकती है।

हाल ही में माइकल क्लेयसे ने एक विषय दिया जो इस विषय को छूता है: http://channel9.msdn.com/events/CPP/C-PP-Con-2014/The-Canonical-Class Canonical-Class


परिचय

सी ++ वैल्यू सेमेन्टिक्स के साथ उपयोगकर्ता परिभाषित प्रकारों के चर का व्यवहार करता है। इसका मतलब है कि वस्तुओं को विभिन्न संदर्भों में पूरी तरह से कॉपी किया गया है, और हमें समझना चाहिए कि "ऑब्जेक्ट की प्रतिलिपि बनाना" वास्तव में क्या है।

आइए एक साधारण उदाहरण पर विचार करें:

class person
{
    std::string name;
    int age;

public:

    person(const std::string& name, int age) : name(name), age(age)
    {
    }
};

int main()
{
    person a("Bjarne Stroustrup", 60);
    person b(a);   // What happens here?
    b = a;         // And here?
}

(यदि आप name(name), age(age) भाग से परेशान हैं, तो इसे सदस्य प्रारंभकर्ता सूची कहा जाता है।)

विशेष सदस्य कार्य

किसी person ऑब्जेक्ट की प्रतिलिपि बनाने का क्या अर्थ है? main समारोह दो विशिष्ट प्रतिलिपि परिदृश्य दिखाता है। प्रारंभिक person b(a); कॉपी कन्स्ट्रक्टर द्वारा किया जाता है। इसका काम मौजूदा वस्तु की स्थिति के आधार पर एक ताजा वस्तु बनाना है। असाइनमेंट b = a कॉपी असाइनमेंट ऑपरेटर द्वारा किया जाता है। इसका काम आम तौर पर थोड़ा अधिक जटिल होता है, क्योंकि लक्ष्य वस्तु पहले से ही कुछ मान्य राज्य में है जिसके साथ निपटा जाना आवश्यक है।

चूंकि हमने न तो कॉपी कन्स्ट्रक्टर और न ही असाइनमेंट ऑपरेटर (न ही विनाशक) घोषित किया है, इन्हें हमारे लिए निहित रूप से परिभाषित किया गया है। मानक से उद्धरण:

[...] प्रतिलिपि निर्माता और कॉपी असाइनमेंट ऑपरेटर, [...] और विनाशक विशेष सदस्य कार्य हैं। [ नोट : कार्यान्वयन इन वर्ग कार्यों को कुछ वर्ग प्रकारों के लिए घोषित करेगा जब कार्यक्रम स्पष्ट रूप से उन्हें घोषित नहीं करता है। अगर उनका उपयोग किया जाता है तो कार्यान्वयन उन्हें निश्चित रूप से परिभाषित करेगा। [...] अंत नोट ] [n3126.pdf धारा 12 §1]

डिफ़ॉल्ट रूप से, किसी ऑब्जेक्ट की प्रतिलिपि बनाने का अर्थ है अपने सदस्यों की प्रतिलिपि बनाना:

गैर-यूनियन क्लास एक्स के लिए अंतर्निहित रूप से परिभाषित प्रतिलिपि निर्माता अपने उप-प्रोजेक्ट की सदस्यवाही प्रतिलिपि करता है। [n3126.pdf अनुभाग 12.8 §16]

गैर-यूनियन क्लास एक्स के लिए अंतर्निहित रूप से परिभाषित प्रति असाइनमेंट ऑपरेटर अपने उप-प्रोजेक्ट्स के सदस्यवार प्रति असाइनमेंट करता है। [n3126.pdf सेक्शन 12.8 §30]

लागू परिभाषाएं

person लिए अंतर्निहित परिभाषित विशेष सदस्य कार्य इस तरह दिखते हैं:

// 1. copy constructor
person(const person& that) : name(that.name), age(that.age)
{
}

// 2. copy assignment operator
person& operator=(const person& that)
{
    name = that.name;
    age = that.age;
    return *this;
}

// 3. destructor
~person()
{
}

सदस्यवार प्रतिलिपि वही है जो हम इस मामले में चाहते हैं: name और age की प्रतिलिपि बनाई गई है, इसलिए हमें एक आत्मनिर्भर, स्वतंत्र person वस्तु मिलती है। निहित रूप से परिभाषित विनाशक हमेशा खाली रहता है। यह इस मामले में भी ठीक है क्योंकि हमने निर्माता में कोई संसाधन नहीं प्राप्त किया है। person विनाशक समाप्त होने के बाद सदस्यों के विनाशकों को पूरी तरह से बुलाया जाता है:

विनाशक के शरीर को निष्पादित करने और शरीर के भीतर आवंटित किसी भी स्वचालित वस्तुओं को नष्ट करने के बाद, कक्षा X के लिए एक विनाशक एक्स के प्रत्यक्ष [...] सदस्यों [n3126.pdf 12.4 §6] के लिए विनाशकों को बुलाता है

संसाधनों का प्रबंधन

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

आइए प्री-स्टैंडर्ड सी ++ में समय पर वापस जाएं। std::string जैसी कोई चीज़ नहीं थी, और प्रोग्रामर पॉइंटर्स से प्यार करते थे। person वर्ग इस तरह दिख सकता है:

class person
{
    char* name;
    int age;

public:

    // the constructor acquires a resource:
    // in this case, dynamic memory obtained via new[]
    person(const char* the_name, int the_age)
    {
        name = new char[strlen(the_name) + 1];
        strcpy(name, the_name);
        age = the_age;
    }

    // the destructor must release this resource via delete[]
    ~person()
    {
        delete[] name;
    }
};

आज भी, लोग अभी भी इस शैली में कक्षाएं लिखते हैं और परेशानी में पड़ते हैं: " मैंने एक व्यक्ति को वेक्टर में धक्का दिया और अब मुझे पागल मेमोरी त्रुटियां मिलती हैं! " याद रखें कि डिफ़ॉल्ट रूप से, ऑब्जेक्ट की प्रतिलिपि बनाने का अर्थ है अपने सदस्यों की प्रतिलिपि बनाना, लेकिन name सदस्य की प्रतिलिपि बनाना केवल एक सूचक की प्रतिलिपि बनाता है, कि चरित्र सरणी को इंगित करता है! इसमें कई अप्रिय प्रभाव हैं:

  1. b माध्यम से a माध्यम से परिवर्तन देखा जा सकता है।
  2. एक बार b नष्ट हो जाने के बाद, a.name एक a.name सूचक है।
  3. यदि a नष्ट हो गया है, तो खतरनाक सूचक को अपरिभाषित व्यवहार को कम करना
  4. चूंकि असाइनमेंट ध्यान में नहीं आता है कि असाइनमेंट से पहले किस name ओर इशारा किया गया है, जल्दी या बाद में आपको जगह पर मेमोरी लीक मिल जाएगी।

स्पष्ट परिभाषाएं

चूंकि सदस्यवाही प्रतिलिपि के पास वांछित प्रभाव नहीं है, इसलिए हमें चरित्र सरणी की गहरी प्रतियां बनाने के लिए कॉपी कन्स्ट्रक्टर और कॉपी असाइनमेंट ऑपरेटर को स्पष्ट रूप से परिभाषित करना होगा:

// 1. copy constructor
person(const person& that)
{
    name = new char[strlen(that.name) + 1];
    strcpy(name, that.name);
    age = that.age;
}

// 2. copy assignment operator
person& operator=(const person& that)
{
    if (this != &that)
    {
        delete[] name;
        // This is a dangerous point in the flow of execution!
        // We have temporarily invalidated the class invariants,
        // and the next statement might throw an exception,
        // leaving the object in an invalid state :(
        name = new char[strlen(that.name) + 1];
        strcpy(name, that.name);
        age = that.age;
    }
    return *this;
}

प्रारंभिकरण और असाइनमेंट के बीच अंतर ध्यान दें: स्मृति रिसाव को रोकने के लिए name देने से पहले हमें पुराने राज्य को फाड़ना होगा। साथ ही, हमें फॉर्म x = x स्व-असाइनमेंट के खिलाफ सुरक्षा करना है। उस चेक के बिना, delete[] name स्रोत स्ट्रिंग युक्त सरणी को हटा देगा, क्योंकि जब आप x = x that.name हैं, तो that.name this->name और that.name दोनों में एक ही सूचक होता है।

अपवाद सुरक्षा

दुर्भाग्यवश, यह समाधान विफल हो जाएगा यदि new char[...] स्मृति थकावट के कारण अपवाद फेंकता है। एक संभावित समाधान स्थानीय चर को पेश करना और बयानों को पुन: व्यवस्थित करना है:

// 2. copy assignment operator
person& operator=(const person& that)
{
    char* local_name = new char[strlen(that.name) + 1];
    // If the above statement throws,
    // the object is still in the same state as before.
    // None of the following statements will throw an exception :)
    strcpy(local_name, that.name);
    delete[] name;
    name = local_name;
    age = that.age;
    return *this;
}

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

अपरिवर्तनीय संसाधन

कुछ संसाधन कॉपी नहीं किए जा सकते हैं या नहीं, जैसे फाइल हैंडल या म्यूटेक्स। उस स्थिति में, प्रतिलिपि देने के बिना कॉपी कन्स्ट्रक्टर और कॉपी असाइनमेंट ऑपरेटर को private रूप से घोषित करें:

private:

    person(const person& that);
    person& operator=(const person& that);

वैकल्पिक रूप से, आप boost::noncopyable से प्राप्त कर सकते हैं या उन्हें हटाए गए (C ++ 0x) घोषित कर सकते हैं:

person(const person& that) = delete;
person& operator=(const person& that) = delete;

तीन का शासन

कभी-कभी आपको एक ऐसी कक्षा को लागू करने की आवश्यकता होती है जो संसाधन का प्रबंधन करे। (कभी भी एक वर्ग में एकाधिक संसाधनों का प्रबंधन न करें, इससे केवल दर्द हो सकता है।) उस स्थिति में, तीन के नियम को याद रखें:

यदि आपको या तो विनाशक घोषित करने की आवश्यकता है, तो कन्स्ट्रक्टर कॉपी करें या खुद को असाइनमेंट ऑपरेटर कॉपी करें, आपको शायद उन सभी तीनों को स्पष्ट रूप से घोषित करने की आवश्यकता है।

(दुर्भाग्यवश, यह "नियम" सी ++ मानक या किसी भी कंपाइलर द्वारा लागू नहीं है जिसे मैं जानता हूं।)

सलाह

अधिकांश समय, आपको संसाधन को स्वयं प्रबंधित करने की आवश्यकता नहीं होती है, क्योंकि मौजूदा श्रेणी जैसे std::string पहले से ही आपके लिए करता है। एक char* का उपयोग करके एक std::string सदस्य का उपयोग करके सरल कोड की तुलना करें और char* का उपयोग करके त्रुटि-प्रवण विकल्प पर क्लिक करें और आपको आश्वस्त होना चाहिए। जब तक आप कच्चे सूचक सदस्यों से दूर रहें, तब तक तीन का नियम आपके स्वयं के कोड से संबंधित होने की संभावना नहीं है।


असल में यदि आपके पास विनाशक है (डिफ़ॉल्ट विनाशक नहीं) तो इसका मतलब है कि आपके द्वारा परिभाषित कक्षा में कुछ स्मृति आवंटन है। मान लें कि कक्षा का उपयोग कुछ क्लाइंट कोड या आपके द्वारा किया जाता है।

    MyClass x(a, b);
    MyClass y(c, d);
    x = y; // This is a shallow copy if assignment operator is not provided

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


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

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

कॉपी असाइनमेंट ऑपरेटर एक विशेष असाइनमेंट ऑपरेटर है जिसे आम तौर पर उसी ऑब्जेक्ट के अन्य लोगों को मौजूदा ऑब्जेक्ट निर्दिष्ट करने के लिए उपयोग किया जाता है।

त्वरित उदाहरण हैं:

// default constructor
My_Class a;

// copy constructor
My_Class b(a);

// copy constructor
My_Class c = a;

// copy assignment operator
b = a;

ऑब्जेक्ट की प्रतिलिपि बनाने का मतलब क्या है? ऑब्जेक्ट्स की प्रतिलिपि बनाने के कुछ तरीके हैं - आइए उन 2 प्रकारों के बारे में बात करें जिनकी आप सबसे अधिक संभावना रखते हैं - गहरी प्रति और उथली प्रतिलिपि।

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

class Car //A very simple class just to demonstrate what these definitions mean.
//It's pseudocode C++/Javaish, I assume strings do not need to be allocated.
{
private String sPrintColor;
private String sModel;
private String sMake;

public changePaint(String newColor)
{
   this.sPrintColor = newColor;
}

public Car(String model, String make, String color) //Constructor
{
   this.sPrintColor = color;
   this.sModel = model;
   this.sMake = make;
}

public ~Car() //Destructor
{
//Because we did not create any custom types, we aren't adding more code.
//Anytime your object goes out of scope / program collects garbage / etc. this guy gets called + all other related destructors.
//Since we did not use anything but strings, we have nothing additional to handle.
//The assumption is being made that the 3 strings will be handled by string's destructor and that it is being called automatically--if this were not the case you would need to do it here.
}

public Car(const Car &other) // Copy Constructor
{
   this.sPrintColor = other.sPrintColor;
   this.sModel = other.sModel;
   this.sMake = other.sMake;
}
public Car &operator =(const Car &other) // Assignment Operator
{
   if(this != &other)
   {
      this.sPrintColor = other.sPrintColor;
      this.sModel = other.sModel;
      this.sMake = other.sMake;
   }
   return *this;
}

}

एक गहरी प्रतिलिपि यह है कि यदि हम किसी ऑब्जेक्ट की घोषणा करते हैं और फिर ऑब्जेक्ट की पूरी तरह से अलग प्रतिलिपि बनाते हैं ... हम 2 ऑब्जेक्ट्स के साथ 2 मेमोरी के सेट में समाप्त होते हैं।

Car car1 = new Car("mustang", "ford", "red");
Car car2 = car1; //Call the copy constructor
car2.changePaint("green");
//car2 is now green but car1 is still red.

अब चलो कुछ अजीब करते हैं। आइए मान लें कि कार 2 या तो प्रोग्राम गलत है या जानबूझकर इसका मतलब है कि वास्तविक स्मृति को साझा करने के लिए कार 1 बनाया गया है। (आमतौर पर ऐसा करने में गलती होती है और कक्षाओं में आमतौर पर कंबल होता है जिस पर चर्चा की जाती है।) दिखाएं कि जब भी आप कार 2 के बारे में पूछते हैं, तो आप वास्तव में कार 1 की मेमोरी स्पेस के सूचक को हल कर रहे हैं ... यह एक उथल-पुथल की तुलना में कम या कम है है।

//Shallow copy example
//Assume we're in C++ because it's standard behavior is to shallow copy objects if you do not have a constructor written for an operation.
//Now let's assume I do not have any code for the assignment or copy operations like I do above...with those now gone, C++ will use the default.

 Car car1 = new Car("ford", "mustang", "red"); 
 Car car2 = car1; 
 car2.changePaint("green");//car1 is also now green 
 delete car2;/*I get rid of my car which is also really your car...I told C++ to resolve 
 the address of where car2 exists and delete the memory...which is also
 the memory associated with your car.*/
 car1.changePaint("red");/*program will likely crash because this area is
 no longer allocated to the program.*/

इसलिए आप जिस भाषा में लिख रहे हैं, इस पर ध्यान दिए बिना, ऑब्जेक्ट्स की प्रतिलिपि बनाने के लिए आपका क्या मतलब है, इस बारे में बहुत सावधान रहें क्योंकि अधिकांश समय आप गहरी प्रतिलिपि चाहते हैं।

कॉपी कन्स्ट्रक्टर और कॉपी असाइनमेंट ऑपरेटर क्या हैं? मैंने पहले से ही उन्हें ऊपर इस्तेमाल किया है। जब आप Car car2 = car1; जैसे कोड टाइप करते हैं तो कॉपी कन्स्ट्रक्टर को कॉल किया जाता है Car car2 = car1; अनिवार्य रूप से यदि आप एक चर घोषित करते हैं और इसे एक पंक्ति में असाइन करते हैं, तो वह तब होता है जब कॉपी कन्स्ट्रक्टर कहा जाता है। असाइनमेंट ऑपरेटर तब होता है जब आप बराबर car2 = car1; उपयोग करते हैं - car2 = car1; । नोटिस कार 2 उसी कथन में घोषित नहीं किया गया है। इन परिचालनों के लिए आपके द्वारा लिखे गए कोड के दो भाग बहुत समान हैं। असल में विशिष्ट डिजाइन पैटर्न में एक और फ़ंक्शन होता है जिसे आप संतुष्ट करने के बाद सबकुछ सेट करने के लिए कॉल करते हैं प्रारंभिक प्रति / असाइनमेंट वैध है - यदि आप मेरे द्वारा लिखे गए लैंडहैंड कोड को देखते हैं, तो फ़ंक्शन लगभग समान होते हैं।

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

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


नियम का तीन मूल रूप से कह रहा है, सी ++ के अंगूठे का नियम है

अगर आपकी कक्षा में से किसी की जरूरत है

  • एक प्रतिलिपि निर्माता ,
  • एक असाइनमेंट ऑपरेटर ,
  • या एक विनाशक ,

स्पष्ट रूप से परिभाषित किया गया है, तो उन सभी तीनों की आवश्यकता होने की संभावना है।

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

यदि आपकी कक्षा प्रबंधन के संसाधन की प्रतिलिपि बनाने के लिए कोई अच्छा अर्थपूर्ण नहीं है, तो कॉपी कन्स्ट्रक्टर और असाइनमेंट ऑपरेटर को private रूप में घोषित ( defining नहीं) द्वारा प्रतिलिपि बनाने पर private

(ध्यान दें कि सी ++ मानक (जो सी ++ 11 है) का आगामी नया संस्करण सी ++ में ले जाने वाले अर्थशास्त्र को जोड़ता है, जो संभवतः तीन के नियम को बदल देगा। हालांकि, मुझे सी ++ 11 सेक्शन लिखने के लिए बहुत कम पता है तीन के नियम के बारे में।)





rule-of-three