You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

Hajoittimet (Destructor)

Hajoittimen nimi on muotoa mato(~) ja sen perään luokan nimi, esim. ~CElain().

Hajoittimen ominaisuuksia:

  • Hajoittimessa tulee vapauttaa muodostimessa varatut muistit.
  • Kutsutaan automaattisesti, kuten muodostintakin.
  • Hajoittimelle ei voi antaa parametreja.
  • Vaikka muodostin on ylikirjoitettu, voidaan silti käyttää oletushajoitinta.

  Kopiomuodostimet (Copy Constructor)

Kopiomuodostin on muodostin, jolle annetaan parametrina referenssi itsensä tyyppiseen olioon. Kopiomuodostimen idea on mahdollistaa olion monistaminen eli kopioiminen. C++ tarjoaa oletuskopiomuodostimen joka osaa tehdä matalan kopioinnin (shallow copy), tarkoittaen että se kopioi kaikkien jäsenmuuttujien arvot, myös osoittimien, mikä on ongelma, kts. Esimerkki 5.

Esimerkki 4: Kopiomuodostimen esittely.

class CElain
{
private:
    float m_Massa;

public:
    CElain() {}            // Tyhjä oletusmuodostin.
    CElain( const CElain&); // Kopiomuodostin
};
Yllä olevassa esimerkissä on esitelty kopiomuodostin (ilman toteutusta). Toteutus voisi olla seuraavanlainen:

CElain::CElain( const CElain& Instanssi)

Unknown macro: {    this->m_Massa = Instanssi.m_Massa; // Kopioidaan annetun olion muuttujan m_Massa arvo omaamme.}

Yllä annettu toteutus on itse asiassa sama kuin oletuskopiomuodostin. Se kopioi kaikkien jäsenmuuttujien arvot.

Esimerkki 5: Kopiomuodostin, kun luokassa on osoittimia.

class CElain
{private:    float m_Massa;    char* m_Nimi;                             // Osoitin.
public:    CElain(char Nimi[])    

Unknown macro: {         m_Nimi = new char[strlen(Nimi) + 1];  // Varataan muistia, annetun merkkijonon verran.     }

    ~CElain()
    
{         delete [] m_Nimi;                     // Vapautetaan varattu muisti.     }
    CElain() { }
    CElain(const CElain& Instanssi)
    
{         this->m_Massa = Instanssi.m_Massa;         this->m_Nimi = Instanssi.m_Nimi;     // Tässä kopioidaan ainoastaan osoittimen arvo, ei itse muistia!     }
};
Yllä oleva kopiomuodostin (joka siis on kuten oletuskopiomuodostin) aiheuttaa ongelmia. Ajatellaan seuraavaa tilannetta:

  • Luodaan ensimmäinen olio, sille annetaan nimi ja varataan muodostimessa tarvittavan määrän muistia nimeä varten.
  • Luodaan toinen olio, käyttämällä kopiomuodostinta, antamalla ensimmäinen olio parametrina.
  • Nyt molemmat oliot omaavat saman massan ARVON ja saman osoittimen ARVON muistiin, jossa sijaitsee nimi. Siis molemmat oliot osoittavat samaan muistialueeseen.
  • Tuhotaan ensimmäinen olio, jolloin kutsutaan sen hajoitin, joka vapauttaa varatun muistin.
  • Nyt meillä on enään toisena luoto olio, jonka m_Nimi osoittaa muistiin, joka juuri vapautettiin!
  • --> Meillä on katastrofi käsissä!

Yllä kuvatun ongelman välttämiseksi voimme kirjoittaa oman kopiomuodostimen, jossa suoritetaan syvä kopiointi (deep copy), eli varataan tarvittava muisti ja kopioidaan merkkijono sinne:

class CElain
{...    CElain(CElain& Instanssi)    

Unknown macro: {         this->m_Massa = Instanssi.m_Massa;         this->m_Nimi = new char[strlen(Instanssi.m_Nimi) + 1]; // Varataan tarvittava muisti merkkijonolle.          strcpy(this->m_Nimi, Instanssi.m_Nimi);                // Tässä kopioidaan merkkijono.     }

};
Tämä kopiomuodostin kopioi osoittimen sisältämän muistin oikein. Nyt voidaan muodostaa haluttu määrä kopioita ja ne käyttäytyvät kuten pitääkin.

  • No labels
You must log in to comment.