5.2.8 · Coding › C++ Programming
Jab ek class kisi resource ko own karti hai (raw new memory, file handle, socket), toh compiler ki automatic copy sirf pointer value ko duplicate karti hai, us cheez ko nahi jis par wo point karta hai. Ab do objects sochte hain ki woh ek hi heap block ko own karte hain. Jab dono destroy hote hain, dono us par delete call karte hain → double free (crash). Rule of Three kehta hai: agar tumne {destructor, copy constructor, copy assignment} mein se ek bhi likha, toh almost certainly teeno likhne padenge, kyunki woh sab ek hi idea describe karte hain — is object ka resource kaise paida hota hai, copy hota hai, aur destroy hota hai?
Destructor ~T() — object ke owned resource ko release karta hai.
Copy constructor T(const T& other) — ek bilkul naya object banata hai other ki copy ke roop mein. Jab ek object doosre se create hota hai tab call hota hai.
Copy assignment operator T& operator=(const T& other) — ek already-existing object ko other ki copy se overwrite karta hai. Jab ek object ko assign kiya jaata hai tab call hota hai.
Key distinction yeh hai:
MyString a = b; // copy CONSTRUCTOR (a abhi born ho raha hai)
MyString c;
c = b; // copy ASSIGNMENT (c already exist karta hai)
= use karte hain, toh woh ek hi function hain."
Yeh sahi lagta hai kyunki dono = token use karte hain. Yeh kyun galat hai: pehla = initialization hai (object abhi exist nahi karta tha → free karne ke liye koi purana resource nahi). Doosra assignment hai (object already ek resource hold karta hai jise tumhe pehle free karna hoga, aur self-assignment se bachna hoga). Fix: ise aise padho — "kya ek naya object create ho raha hai?" Agar haan → constructor; agar nahi → assignment.
Default copy ek member-wise copy karta hai. Pointer member ke liye, member ko copy karne ka matlab hai address ko copy karna — yeh ek shallow copy hai. Deep copy naya memory allocate karta hai aur contents ko copy karta hai.
Shallow copy ka aftermath:
a.data ──┐
├──► [ "hi\0" ] ek buffer, do owners
b.data ──┘
Jab a aur b dono destruct hote hain: delete[] (same ptr) do baar run hota hai → undefined behavior . Saath hi, a ke through likhna silently b ko corrupt karta hai (aliasing).
Humein ek class chahiye jo char* own kare. Chaliye har member ko reason karke banate hain ki kya hona chahiye.
#include <cstring> // strlen, strcpy
class MyString {
char* data; // owned resource
std :: size_t len;
public:
// --- normal constructor ---
MyString ( const char* s = "" ) {
len = std :: strlen (s);
data = new char [len + 1 ]; // +1 '\0' ke liye
std :: strcpy (data, s);
}
len+1 kyun? Strings ko null terminator slot chahiye hota hai.
// --- (1) Destructor: resource kaise marta hai ---
~ MyString () {
delete[] data; // [] kyunki humne new[] kiya tha
}
delete[] kyun? Array-new ko array-delete ke saath pair karna zaroori hai, warna UB.
// --- (2) Copy constructor: copy ke roop mein born hona ---
MyString ( const MyString & other) {
len = other.len;
data = new char [len + 1 ]; // APNA memory — deep copy
std :: strcpy (data, other.data);
}
Fresh allocate kyun karte hain? Taaki naya object ek independent buffer own kare; ek ko destroy karna doosre ko affect na kare.
// --- (3) Copy assignment: ek existing object ko overwrite karna ---
MyString & operator = ( const MyString & other ) {
if ( this == & other) return * this ; // self-assignment guard
delete[] data; // PURANA resource free karo
len = other.len;
data = new char [len + 1 ]; // naya allocate karo
std :: strcpy (data, other.data);
return * this ; // chaining a=b=c ke liye
}
};
Common mistake "Self-assignment guard paranoid hai — kaun
a = a likhta hai?"
Yeh unnecessary lagta hai. Yeh kyun galat hai: aliasing indirectly hoti hai — arr[i] = arr[j] jab i==j ho, ya ek hi object ke do references ho. Guard ke bina , tum pehle delete[] data karte ho, phir strcpy(data, other.data) — lekin other.data wohi freed data hai! Tum garbage se copy kar rahe ho. Fix: if (this == &other) return *this; line.
operator= mein purana resource free karna bhool jaana.
Copy-construction allocate karta hai bina koi purani buffer release kiye. Assignment similar lagti hai, isliye log constructor body copy kar lete hain aur delete[] data; bhool jaate hain. Result: memory leak — purana buffer orphan ho jaata hai. Fix: pehle free karo (self-check ke baad), phir allocate karo.
Copy-and-swap idiom (elegant alternative)
other ko by value lo (yeh copy constructor reuse karta hai ), phir guts swap karo:
MyString & operator = ( MyString other ) { // by value → copies
std :: swap (data, other.data);
std :: swap (len, other.len);
return * this ; // 'other' (purana guts) yahan marta hai
}
Self-assignment-safe aur exception-safe for free , kyunki saari allocation *this ko touch karne se pehle hoti hai. Purana buffer automatically free hota hai jab other destruct hota hai.
Worked example Example 1 — copy constructor fire hota hai
MyString a ( "cat" );
MyString b = a; // copy ctor
Ctor kyun, assignment kyun nahi? b create ho raha hai . Iske baad, a.data != b.data (do buffers), dono mein "cat" hai. Dono ko destroy karna safe hai.
Worked example Example 2 — assignment fires, purana buffer freed hota hai
MyString a ( "cat" );
MyString b ( "elephant" );
b = a; // copy assignment
Step 1 — self-check kyun? &a != &b, toh aage badhte hain.
Step 2 — delete[] data kyun? b ne "elephant" ka buffer hold kiya tha; use release karna hoga warna leak hoga.
Step 3 — new+strcpy kyun? b ko apna "cat" milta hai. Ab dono destroy karne ke liye safe hain.
Worked example Example 3 —
default (broken) version kya karta hai
// Koi user copy ops nahi likhe → compiler shallow-copies
MyString a ( "hi" );
{ MyString b = a; } // b yahan marta hai → delete[] data
// a.data ab dangling hai; a ka destructor → delete[] dobara → CRASH
Crash kyun? Dono objects ek pointer share karte the; delete[] us par do baar run hua.
Rule of Five move constructor aur move assignment (C++11) add karta hai temporaries se resources cheaply steal karne ke liye. Rule of Zero : classes ko RAII types (std::string, std::vector, std::unique_ptr) ke through resources own karne ke liye design karo taaki tum panchon mein se koi bhi na likho — members tumhare liye copying handle kar lete hain.
Rule of Three kaunse teen members se concerned hai? Destructor, copy constructor, aur copy assignment operator.
Rule of Three kyun exist karta hai? Agar ek class manually resource manage karti hai, toh double-free, leaks, aur aliasing bugs se bachne ke liye teeno ki zaroorat hoti hai.
Copy constructor vs copy assignment ko trigger se distinguish karo. Copy ctor: ek naya object doosre se create hota hai. Copy assignment: ek already-existing object overwrite hota hai.
Shallow copy vs deep copy kya hota hai? Shallow pointer copy karta hai (shared buffer); deep naya memory allocate karta hai aur contents copy karta hai.
Pointer ki default shallow copy se do bugs kya hain? Destruction par double free, aur aliasing (ek mein likhna doosre ko corrupt karta hai).
Copy assignment mein self-assignment guard kyun lagana hoga? Iske bina, data ko copy karne se pehle free karna source ko destroy kar deta hai (jaise a = a).
operator= ko purana resource kyun free karna chahiye lekin copy ctor ko nahi?Assigned-to object already ek buffer own karta hai (free nahi kiya toh leak); constructed object ke paas abhi koi buffer nahi hota.
Copy assignment ke liye conventional signature kya hai? T& operator=(const T& other) — chaining ke liye reference return karta hai.
Copy-and-swap tumhe kya deta hai? Value parameter se copy karke phir swap karne se self-assignment safety aur exception safety free mein milti hai.
new[] ko delete[] ke saath kyun pair karna chahiye?Mismatched new/delete forms undefined behavior hai.
Rule of Zero kya hai? RAII member types (string, vector, unique_ptr) use karo taaki tum special members mein se koi bhi na likho.
Recall Feynman: ek 12-saal ke bacche ko explain karo
Socho har object ke paas ek toy box (memory) hai aur ek note jis par box ka address likha hai. Lazy copy sirf note ko photocopy karta hai, toh ab do bacche ek hi box ko point karte hain. Jab playtime khatam hoti hai, dono bacche box ko phenkne ki koshish karte hain — lekin ek hi box ko do baar nahi phek sakte, toh sab kuch toot jaata hai! Rule of Three kehta hai: agar tumne kisi bacche ko ek box diya, toh tumhe unhe teen cheezein sikhani hain — box ko saaf karna , janam lete waqt box ki apni copy banana , aur baad mein box badalna apni copy se . Teeno karo ya koi nahi.
"DCA — Destroy, Copy-create, Copy-assign."
"Agar ek likha, teeno likho — Death, Cloning, Assignment."
Buffer ke teen life events: copy se born → assignment se reborn → destructor mein marta hai.
releases resource with delete[]
prevents freeing before copy
Default copy is member-wise
Two objects share one buffer
Double free and aliasing bugs
Copy constructor T const T&
Copy assignment operator=
Deep copy allocates new memory