Ivan Sergio Borgonovo ha scritto:
On Tue, Aug 19, 2003 at 11:17:35PM +0200, Davide Bolcioni wrote:
punto& operator= (const punto& p) { // Nota 5
if (this != &p) { // Nota 6
x = other.x;
y = other.y;
}
return *this;
}
[6] quando si scrive l'operatore di assegnamento, occorre chiedersi se
per caso non ci si sta scrivendo addosso (nei costruttori non può
succedere, creano un oggetto nuovo); ancora una volta nel caso in esame
posto. Tecnicamente questo approccio non è correttissimo per questioni
legate alle eccezioni, ma mi pare il caso di affrontare una cosa alla
volta.
Non ho capito dove vuoi parare.
Prima di usare =, hai gia` costruito gli oggetti. I problemi di eccezioni
> dovrebbero essere gia` stati risolti.
A meno che tu ti riferisca a roba tipo copiare un vector di 15 elementi in
> uno che ha un default constructor di 10...
Ma la stai prendendo larga, pero` se cominci a fare roba astrusa nel =op.
> bhe... ovvio che te la devi gestire...
template < typename CoordType > class punto {
...
punto& operator= (const punto& rhs) {
if (this != &rhs) {
x = other.x;
y = other.y; // Nota 1.
}
return *this;
}
}
Finchè CoordType è un tipo predefinito, al punto [1] non succede
niente; se è una classe che fornisce un intero con precisione
infinita e il *suo* operatore di assegnamento solleva un'eccezione
io ho un punto che ha la nuova x ma la vecchia y. Un idioma corretto
è il seguente:
punto& operator= (const punto& rhs) {
CoordType tx(rhs.x);
CoordType ty(rhs.y);
std::swap(x, tx);
std::swap(y, ty);
return *this;
}
ovvero prima mi procuro le risorse che possono risultare in
eccezioni, in modo che se capitano non cambio lo stato, poi
cambio lo stato con std::swap(). Il motivo per cui swap() può
farcela senza eccezioni sta nel fatto che il suo compito è
scambiare due oggetti esistenti: si è visto in genere che ciò
si riesce a fare senza dover causare eccezioni. Chi fornisce
CoordType dovrebbe fornire uno swap() appropriato: quello di
default usa l'operatore di assegnamento e saremmo da capo.
Si noti che apparentemente il codice sopra indicato è meno efficiente
in quanto fa una copia supplementare, ma in realtà:
- se CoordType è un tipo predefinito, il compilatore sa ottimizzarlo
comunque a fondo e non sono certo due copie in una variabile locale
a spaventarlo;
- se CoordType non è predefinito ma il suo operatore di assegnamento
non solleva eccezioni, posso scrivere una variante apposta qualora
scoprissi che l'operazione è critica dal punto di vista della
performance;
- se l'operatore di assegnamento solleva eccezioni, bisogna scriverlo
in quel modo comunque (se poi salta fuori che è davvero cruciale per
la performance, può darsi che si decida di sacrificare il risultato
corretto ma il discorso diventa assai complicato).
Scrivendo un template, si sta dicendo al compilatore: questo codice va
bene per *qualsiasi* CoordType, fidati. Occorre cautelarsi.
Davide Bolcioni
--
Paranoia is a survival asset.
|