rule of three
Főnév
rule of three (tsz. rule of threes)
- (informatika) A „Rule of Three” (Hármas szabály) a C++ egyik alapelve, amely az erőforráskezeléshez (főleg dinamikusan foglalt memória, fájlok, mutexek stb.) kapcsolódó osztályok megírásakor játszik kulcsszerepet. A szabály kimondja, hogy ha egy osztálynak szüksége van a destruktor (
~ClassName), a másoló konstruktor (ClassName(const ClassName&)) vagy a másoló értékadó operátor (operator=) explicit definiálására, akkor a másik kettőt is definiálni kell. Ez azért szükséges, mert ezek az elemek együtt kezelik a mély másolást (deep copy), és így biztosítják az erőforrások biztonságos és helyes másolását, illetve felszabadítását.
💡 A probléma gyökere: Shallow copy vs. Deep copy
Shallow copy (sekély másolat)
A másolás során csak a mutató kerül átmásolásra, nem maga az adathalmaz. Ez dupla felszabadításhoz (double free) és hibás működéshez vezethet.
class MyClass {
int* data;
public:
MyClass(int value) {
data = new int(value);
}
~MyClass() {
delete data;
}
};
Itt, ha példányosítunk két objektumot, majd az egyiket átmásoljuk a másikba, mindkettő ugyanarra a memóriaterületre mutat. Az egyik objektum destruktora törli az erőforrást, a második pedig ismét megpróbálja törölni ugyanazt, ami memóriahibához vezet.
🔁 A három elem
1. Másoló konstruktor
Akkor hívódik meg, amikor egy új objektumot egy már létező példány másolatával hozunk létre.
MyClass a(10);
MyClass b = a; // másoló konstruktor
Ha a másoló konstruktor nincs definiálva, a fordító alapértelmezettet generál, ami sekély másolatot készít.
2. Másoló értékadó operátor
Akkor hívódik meg, amikor egy már létező objektumot másik objektummal akarunk felülírni.
MyClass a(10);
MyClass b(20);
b = a; // értékadó operátor
Ez szintén sekély másolatot végez, ha nem írjuk felül.
3. Destruktor
Akkor hívódik meg, amikor egy objektum elpusztul (például kilép egy blokkhatárból, vagy delete-et hívunk rá). Ha erőforrásokat foglalunk az objektumban (például new-val memóriát), itt kell felszabadítani őket (delete).
✅ Példa a Rule of Three megvalósítására
class MyClass {
int* data;
public:
MyClass(int value) {
data = new int(value);
}
// Másoló konstruktor
MyClass(const MyClass& other) {
data = new int(*other.data);
}
// Másoló értékadó operátor
MyClass& operator=(const MyClass& other) {
if (this != &other) { // ön-hozzárendelés ellenőrzése
delete data; // régi adat felszabadítása
data = new int(*other.data);
}
return *this;
}
// Destruktor
~MyClass() {
delete data;
}
void print() const {
std::cout << *data << std::endl;
}
};
Ezzel biztosítjuk, hogy minden példány saját memóriával rendelkezik, és az erőforrások megfelelően kezelve vannak.
⚠️ Mi történik, ha csak egyet definiálunk?
- Ha csak destruktort írunk: a másolás sekély marad, ami memóriahibákhoz vezet.
- Ha csak másoló konstruktort írunk: az értékadó operátor nem fog megfelelően működni.
- Ha csak értékadó operátort írunk: a másoló konstruktor hibás lehet, különösen ha konténerben használjuk az osztályt (például
std::vector<MyClass>).
📦 Modern alternatívák: Rule of Five, Rule of Zero
Rule of Five
A C++11 óta, ha egy osztály erőforrásokat kezel, nemcsak a három fenti tagfüggvény, hanem a mozgató konstruktor és a mozgató értékadó operátor is fontos lehet:
- Mozgató konstruktor:
ClassName(ClassName&&) - Mozgató értékadó:
ClassName& operator=(ClassName&&)
Ez a Rule of Five (Ötös szabály): ha egyet explicit definiálsz, az összes többit is definiáld.
Rule of Zero
Ha modern C++ eszközöket használsz, mint az std::vector, std::string, std::unique_ptr, akkor nincs szükség saját destruktorra, másolóra, stb. Ez a Rule of Zero: bízd a kezelést az RAII-alapú eszközökre.
class MyBetterClass {
std::unique_ptr<int> data;
public:
MyBetterClass(int value) : data(std::make_unique<int>(value)) {}
void print() const {
std::cout << *data << std::endl;
}
};
Itt nincs szükség a három tagfüggvényre – az std::unique_ptr mindent elintéz.
🔁 Összefoglalás
| Fogalom | Mikor hívódik meg? | Feladat |
|---|---|---|
| Destruktor | Objektum megsemmisülésekor | Erőforrás felszabadítása |
| Másoló konstruktor | Új példány létrehozása másolatként | Mély másolat készítése |
| Másoló operátor | Létező példány felülírásakor | Régi adat törlése, új másolása |
🎯 Mikor használd a Rule of Three-t?
- Ha nyers erőforrást (
new,malloc, fájlkezelés, stb.) kezelsz. - Ha a másolatkészítés nem triviális.
- Ha biztosítani akarod az objektum invariánsainak megtartását másoláskor is.
- rule of three - Szótár.net (en-hu)
- rule of three - Sztaki (en-hu)
- rule of three - Merriam–Webster
- rule of three - Cambridge
- rule of three - WordNet
- rule of three - Яндекс (en-ru)
- rule of three - Google (en-hu)
- rule of three - Wikidata
- rule of three - Wikipédia (angol)