C++
The rule of three
Kod som alltid genereras
• Det finns tre metoder som alltid tillverkas 1.Kopieringskonstruktorn
2.Tilldelningsoperatorn 3.Destruktorn
• Förutom dessa tillverkas en
Varför är det så?
• Programmerare förväntar sig kunna göra tilldelningar och värdeanrop.
• A a1; A a2;
• A a3 = a1; // copy-constructor
• a2 = a1; // operator=
• foo(a1);
• void foo(A a) { … // call by value
Copy constructor
• Koden för kopiekonstruktorn genereras i compile-time.
• Den genererade koden kopierar varje fält. Detta är ofta rätt.
class A {
…
int x;
std::string s;
std::vector<int> v;
Copy constructor
• För klasser som använder medlemspekare till dynamiskt allokerat minne blir det fel.
Exempel:
Vektor v1;
{
Vektor v2 = v1;
}
v1
data
v2
data
Vektor v1;
{
Vektor v2 = v1;
}
När blocket avslutas så destrueras den lokala variabeln v2.
Destruktorn körs.
~Vektor() {
delete [] data;
}
v1
data
v2
data
copy constructor
• Vad som borde hända är att vi först skapar eget utrymme åt kopians data
• Därefter kopierar data med en
loop. v2
data
v1
data
operator=
• Precis som för kopiering förväntas tilldelning alltid fungera.
• Koden som man ska skriva är ganska lik kopiekonstruktorns kod.
Vector v1;
Vector v2;
…
v2 = v1
v2
data
v1
data
Tilldelning
Om exception kastas när nya minnet ska allokeras så blir v2 odefinierad
?
v2 = v1
v2data
v1
data
tmp
Säkrare tilldelning
Även om det kastas exception är v2
Tilldelning
• Om minnet man redan har räcker.
Kan man skriva över det.
• Var noga med tillståndet
v2
data
v1
data
Effektiv kopiering
• Använd inte memcpy på objekt i vektorn
ipekare epekare
ipekare epekare
ipekare epekare
ipekare epekare
Tilldelning
• Specialfall v = v
• Jämför this med parametern v.
… operator=(const Vector & v){
• Det finns ett bra och ett potentiellt mycket långsamt sätt att jämföra
this == &v
*this == v
Summering
• Ni måste kunna vilka metoder som
konstrueras i compile-time även om ni inte definierat dem
• Ni måste kunna hantera dynamiskt minne