copy assignment operator (tsz. copy assignment operators)
A másoló értékadó operátor szintaxisa:
ClassName& operator=(const ClassName& other);
Ez a művelet akkor hajtódik végre, amikor már létező objektumra értékül adunk egy másikat:
Szamok a(10, 1.0);
Szamok b(5, 2.0);
b = a; // ← itt hívódik meg a másoló értékadó operátor
Ha nem definiálod, a fordító automatikusan létrehoz egy shallow copy-t végző másoló operátort. Ez azt jelenti, hogy a tagváltozók értékeit egyszerűen átmásolja, akkor is, ha az egyik pointer. Ez veszélyes lehet dinamikus memóriakezelés esetén:
class Szamok {
double* tomb;
unsigned meret;
// ...
};
Ebben az esetben a tomb
tömb pointerként másolódik, tehát két objektum ugyanarra a memóriaterületre mutat, ami duplikált delete
hívásokhoz vezethet (undefined behavior). Ezért ha van dinamikus memória, saját másoló operátort kell írni!
Szamok a(5, 3.14);
Szamok b(5, 2.71);
b = a; // automatikus shallow copy
// Mindkettő ugyanazt a tomb memóriát használja
Amikor b
destruktora meghívódik, felszabadítja a tomb
tömböt. Ezután a
destruktora szintén megpróbálja felszabadítani ugyanazt, és itt jön a hiba: double delete.
A helyes implementáció így néz ki:
Szamok& Szamok::operator=(const Szamok& other) {
if (this != &other) { // Ön-hozzárendelés ellenőrzése
delete tomb; // Saját memória felszabadítása
meret = other.meret;
tomb = new double; // Új memória foglalása
for (unsigned i = 0; i < meret; ++i) {
tomb = other.tomb; // Érték másolás
}
}
return *this;
}
this != &other
→ megelőzi az ön-hozzárendelést (a = a;
).delete tomb
→ felszabadítja a régi tömböt.new double
→ új helyet foglal.tomb = other.tomb
→ érték másolás történik, nem pointer.
class Szamok {
unsigned meret;
double* tomb;
public:
Szamok(unsigned meret, double ertek = 0.0) : meret(meret) {
tomb = new double;
for (unsigned i = 0; i < meret; ++i) {
tomb = ertek;
}
}
~Szamok() {
delete tomb;
}
// Másoló konstruktor
Szamok(const Szamok& other) : meret(other.meret) {
tomb = new double;
for (unsigned i = 0; i < meret; ++i) {
tomb = other.tomb;
}
}
// Másoló értékadó operátor
Szamok& operator=(const Szamok& other) {
if (this != &other) {
delete tomb;
meret = other.meret;
tomb = new double;
for (unsigned i = 0; i < meret; ++i) {
tomb = other.tomb;
}
}
return *this;
}
};
Ha egy osztály:
Ez a “Rule of Three”. Modern C++-ban már létezik a “Rule of Five” is, amelyhez a move constructor
és move assignment
is tartozik.
operator=const&
): érték másolása (új példányt csinál)operator=&&
): erőforrások átvétele (hatékonyabb, lásd std::move
)
std::vector
, std::string
, vagy más RAII-t használó típust, akkor nem szükséges saját másoló értékadó operátort írni.operator=
törölhető:Szamok& operator=(const Szamok&) = delete;
A másoló értékadó operátor: