Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> C++

C++ में Rule of Three (थ्री का नियम)


Rule of Three C++ में एक क्लास डिजाइन दिशानिर्देश है: यदि आपकी क्लास को निम्न में से किसी की स्पष्ट परिभाषा की आवश्यकता है, तो संभवतः तीनों की आवश्यकता होगी:

  1. कॉपी कंस्ट्रक्टर (Class(const Class&))
  2. कॉपी असाइनमेंट ऑपरेटर (Class& operator=(const Class&))
  3. डिस्ट्रक्टर (~Class())

क्यों?

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

समस्या: डिफॉल्ट शैलो कॉपी

class BadString {
    char* data;
    size_t len;
public:
    BadString(const char* s) : len(strlen(s)) {
        data = new char[len + 1];
        strcpy(data, s);
    }
    // कोई कॉपी कंस्ट्रक्टर, असाइनमेंट, डिस्ट्रक्टर नहीं!
};

int main() {
    BadString s1("Hello");
    BadString s2 = s1;  // शैलो कॉपी - दोनों समान data पॉइंटर शेयर करते हैं!
    // s1 और s2 दोनों नष्ट होंगे → डबल फ्री → क्रैश!
}

समाधान: Rule of Three लागू करना

#include <iostream>
#include <cstring>
using namespace std;

class GoodString {
    char* data;
    size_t len;
    
public:
    // 1. कंस्ट्रक्टर
    GoodString(const char* s = "") : len(strlen(s)) {
        data = new char[len + 1];
        strcpy(data, s);
        cout << "Constructed: " << data << endl;
    }
    
    // 2. डिस्ट्रक्टर
    ~GoodString() {
        cout << "Destroyed: " << (data ? data : "null") << endl;
        delete[] data;
    }
    
    // 3. कॉपी कंस्ट्रक्टर (डीप कॉपी)
    GoodString(const GoodString& other) : len(other.len) {
        data = new char[len + 1];
        strcpy(data, other.data);
        cout << "Copy constructed: " << data << endl;
    }
    
    // 4. कॉपी असाइनमेंट ऑपरेटर
    GoodString& operator=(const GoodString& other) {
        cout << "Copy assigned: " << other.data << endl;
        if (this != &other) {  // सेल्फ-असाइनमेंट चेक
            delete[] data;       // पुराना रिसोर्स रिलीज
            len = other.len;
            data = new char[len + 1];
            strcpy(data, other.data);
        }
        return *this;
    }
    
    void print() const { cout << data << endl; }
};

int main() {
    GoodString s1("Hello");
    GoodString s2 = s1;        // कॉपी कंस्ट्रक्टर
    GoodString s3("World");
    s3 = s1;                   // कॉपी असाइनमेंट
    s1.print(); s2.print(); s3.print();
}  // तीनों डिस्ट्रक्ट होते हैं - कोई डबल फ्री नहीं!

आउटपुट

Constructed: Hello
Copy constructed: Hello
Constructed: World
Copy assigned: Hello
Hello
Hello
Hello
Destroyed: Hello
Destroyed: Hello
Destroyed: Hello

C++11: Rule of Five (फाइव का नियम)

C++11 में मूव सेमांटिक्स जुड़ने के बाद, यदि आप मूव ऑपरेशन्स को परिभाषित करते हैं, तो पांचों की आवश्यकता होती है:

  1. डिस्ट्रक्टर
  2. कॉपी कंस्ट्रक्टर
  3. कॉपी असाइनमेंट
  4. मूव कंस्ट्रक्टर (Class(Class&&))
  5. मूव असाइनमेंट (Class& operator=(Class&&))
class ModernString {
    char* data;
    size_t len;
public:
    // ... उपरोक्त सभी ...
    
    // 5. मूव कंस्ट्रक्टर
    ModernString(ModernString&& other) noexcept 
        : data(other.data), len(other.len) {
        other.data = nullptr;
        other.len = 0;
        cout << "Move constructed\n";
    }
    
    // 6. मूव असाइनमेंट
    ModernString& operator=(ModernString&& other) noexcept {
        if (this != &other) {
            delete[] data;
            data = other.data;
            len = other.len;
            other.data = nullptr;
            other.len = 0;
            cout << "Move assigned\n";
        }
        return *this;
    }
};

Rule of Zero (शून्य का नियम) - आधुनिक बेस्ट प्रैक्टिस

रॉ पॉइंटर्स के बजाय std::string, std::vector, std::unique_ptr जैसे RAII टाइप्स उपयोग करें। फिर आपको कोई भी स्पेशल मेंबर फंक्शन लिखने की आवश्यकता नहीं - कंपाइलर-जनरेटेड सही काम करते हैं!

#include <string>
#include <vector>
#include <memory>

class BestPractice {
    std::string name;           // खुद मैनेज करता है
    std::vector<int> data;      // खुद मैनेज करता है
    std::unique_ptr<Resource> res; // खुद मैनेज करता है
    // कोई डिस्ट्रक्टर, कॉपी, मूव नहीं चाहिए - Rule of Zero!
};
  1. - C++ में रूल ऑफ थ्री बनाम रूल ऑफ फाइव?

    रूल ऑफ थ्री C++ का उपयोग करते समय एक थंब रूल है। यह एक तरह की अच्छी प्रैक्टिस रूल है जो कहती है कि यदि आपकी क्लास को निम्न में से किसी की आवश्यकता है: एक कॉपी कंस्ट्रक्टर, एक असाइनमेंट ऑपरेटर, या एक डिस्ट्रक्टर, स्पष्ट रूप से परिभाषित, तो इसे संभवतः उन सभी तीन की आवश्यकता होगी। यह क्यों है? ऐसा इस

  1. - C++ में 'रूल ऑफ थ्री' क्या है?

    रूल ऑफ थ्री (Rule of Three) C++ में एक अनुभव-आधारित नियम (rule of thumb) है। यह एक अच्छी प्रथा का नियम है जो कहता है कि यदि आपके क्लास को निम्न में से किसी की भी स्पष्ट रूप से आवश्यकता है: एक कॉपी कंस्ट्रक्टर, एक असाइनमेंट ऑपरेटर, या एक डिस्ट्रक्टर, तो संभवतः उसे तीनों की आवश्यकता होगी। ऐसा क्यों

  1. - C++ में असाइनमेंट ऑपरेटर्स

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