assignment operator (tsz. assignment operators)
=
) túlterhelése C++-banAz értkadó operátor (=
) a C++ egyik legalapvetőbb operátora, amely lehetővé teszi egy objektum másik objektumhoz való hozzárendelését. Alapértelmezés szerint a fordító létrehoz egy alapértelmezett értékadó operátort, de bizonyos esetekben ezt érdemes túlterhelni.
=
) működéseAmikor egy osztályobjektumot egy másikhoz rendelünk, a C++ alapértelmezett másolási mechanizmust használ: bitmásolást végez az adattagokon.
=
operátorra#include <iostream>
using namespace std;
class Auto {
public:
string marka;
int evjarat;
};
int main() {
Auto auto1;
auto1.marka = "Toyota";
auto1.evjarat = 2020;
Auto auto2;
auto2 = auto1; // Alapértelmezett értékadás
cout << "auto2: " << auto2.marka << ", " << auto2.evjarat << endl;
return 0;
}
auto2: Toyota, 2020
💡 Megjegyzés: Az alapértelmezett =
operátor egyszerű másolást végez a tagváltozókon. Ez jól működik egyszerű típusoknál, de problémát okozhat dinamikusan foglalt adatoknál!
=
operátort?Ha egy osztály dinamikusan foglalt memóriát használ (new
és delete
), akkor az alapértelmezett =
operátor csak a pointert másolja, nem az általa mutatott adatot. Ez memóriaszivárgáshoz vagy dupla felszabadításhoz vezethet.
=
operátorralclass Dinamikus {
public:
int* adat;
Dinamikus(int ertek) {
adat = new int(ertek);
}
~Dinamikus() {
delete adat;
}
};
int main() {
Dinamikus obj1(10);
Dinamikus obj2(20);
obj2 = obj1; // PROBLÉMA!
return 0;
}
💥 Miért rossz? - obj2 = obj1;
során mindkét objektum ugyanarra a memóriacímre fog mutatni. - Amikor obj2
destruktora lefut, felszabadítja a memóriát. - Ezután obj1
destruktora is megpróbálja újra felszabadítani ugyanazt a memóriát → programhiba (double delete).
=
operátor helyes túlterheléseA megoldás: mélymásolás végrehajtása az operátor túlterhelésével.
=
operátor túlterhelés#include <iostream>
using namespace std;
class Dinamikus {
public:
int* adat;
// Konstruktor
Dinamikus(int ertek) {
adat = new int(ertek);
}
// Másoló értékadó operátor
Dinamikus& operator=(const Dinamikus& masik) {
if (this != &masik) { // Önvisszaadás elkerülése
delete adat; // Régi memória felszabadítása
adat = new int(*masik.adat); // Új memóriafoglalás és másolás
}
return *this; // Láncolt hozzárendelés támogatása
}
// Kiíró függvény
void kiir() {
cout << "Ertek: " << *adat << endl;
}
// Destruktor
~Dinamikus() {
delete adat;
}
};
int main() {
Dinamikus obj1(10);
Dinamikus obj2(20);
obj2 = obj1; // Helyes értékadás
obj1.kiir();
obj2.kiir();
return 0;
}
Ertek: 10 Ertek: 10
this != &masik
), hogy ne töröljük saját adatainkat.delete adat
).new int(...)
) és bemásoljuk az értéket.return *this;
→ lehetővé teszi a láncolt hozzárendelést (a = b = c
).
a = b = c
) támogatásaA helyesen túlterhelt =
operátor lehetővé teszi az értékadás láncolását:
Dinamikus a(5), b(10), c(15);
a = b = c; // Minden objektum a c értékét kapja meg
a.kiir(); // 15
b.kiir(); // 15
c.kiir(); // 15
💡 Ez azért működik, mert a túlterhelt =
operátor *this
-t ad vissza.
=
operátor túlterhelése mozgás szemantikával (C++11)C++11 bevezette a mozgás szemantikát, amely gyorsabb és hatékonyabb memóriahasználatot biztosít.
class Dinamikus {
public:
int* adat;
// Konstruktor
Dinamikus(int ertek) {
adat = new int(ertek);
}
// Mozgató értékadó operátor (C++11)
Dinamikus& operator=(Dinamikus&& masik) noexcept {
if (this != &masik) {
delete adat; // Régi erőforrás felszabadítása
adat = masik.adat; // Mutató átvétele
masik.adat = nullptr; // Megakadályozza a dupla felszabadítást
}
return *this;
}
// Destruktor
~Dinamikus() {
delete adat;
}
};
💡 A mozgásos értékadás előnye:
- Gyorsabb, mert nincs szükség új memóriafoglalásra és másolásra. - Csak a mutatókat mozgatja, nem az egész objektumot.
=
operátort?✔ Ha az osztály dinamikusan foglalt memóriát (new
-t) használ.
✔ Ha az osztály olyan erőforrást kezel, amelyet egy másik objektumtól függetlenül kell másolni (pl. fájlkezelés, adatbázis-kapcsolatok).
✔ Ha az osztályt egyedi adattagokkal (pl. std::unique_ptr
) használjuk.
🚀 Ha az osztály nem tartalmaz dinamikusan foglalt erőforrásokat, akkor az alapértelmezett =
operátor megfelelő!
=
operátor egyszerű bitmásolást végez, ami dinamikus memóriával veszélyes lehet.=
operátor mélymásolást végez és elkerüli az önhozzárendelést.operator=(T&&)
) gyorsabb és hatékonyabb.operator=
visszatérési értéke *this
, hogy támogassa a láncolt hozzárendelést.