assignment operator
Főnév
assignment operator (tsz. assignment operators)
Értékadó operátor (=) túlterhelése C++-ban
Az é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.
1. Az alapértelmezett értékadó operátor (=) működése
Amikor 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.
Példa az alapértelmezett = 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;
}
Kimenet:
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!
2. Miért kell túlterhelni az = 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.
Hibás működés alapértelmezett = operátorral
class 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).
3. Az = operátor helyes túlterhelése
A megoldás: mélymásolás végrehajtása az operátor túlterhelésével.
Helyes = 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;
}
Kimenet:
Ertek: 10 Ertek: 10
Mit csinálunk másként?
- Ellenőrizzük az önhozzárendelést (
this != &masik), hogy ne töröljük saját adatainkat. - Felszabadítjuk az előző memóriát (
delete adat). - Új memóriaterületet foglalunk (
new int(...)) és bemásoljuk az értéket. return *this;→ lehetővé teszi a láncolt hozzárendelést (a = b = c).
4. Láncolt értékadás (a = b = c) támogatása
A 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.
5. Az = 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.
6. Mikor kell túlterhelni az = 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ő!
7. Összegzés
- Az alapértelmezett
=operátor egyszerű bitmásolást végez, ami dinamikus memóriával veszélyes lehet. - A helyesen túlterhelt
=operátor mélymásolást végez és elkerüli az önhozzárendelést. - C++11-ben a mozgásos értékadó operátor (
operator=(T&&)) gyorsabb és hatékonyabb. - Az
operator=visszatérési értéke*this, hogy támogassa a láncolt hozzárendelést.
- assignment operator - Szótár.net (en-hu)
- assignment operator - Sztaki (en-hu)
- assignment operator - Merriam–Webster
- assignment operator - Cambridge
- assignment operator - WordNet
- assignment operator - Яндекс (en-ru)
- assignment operator - Google (en-hu)
- assignment operator - Wikidata
- assignment operator - Wikipédia (angol)