erlug
[Top] [All Lists]

Re: [Erlug] c e classi

To: erlug@xxxxxxxxxxxxxx
Subject: Re: [Erlug] c e classi
From: Davide Bolcioni <db_erlug@xxxxxxxx>
Date: Wed, 20 Aug 2003 22:00:24 +0200
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.


<Prev in Thread] Current Thread [Next in Thread>