Prev Next Up Title Contents Index

throw, try ja catch


C++:ssa (ANSI ehdotus 2.0?) on poikkeusten käsittelyä varten komento, jolla "heitetään virhe": throw. Kun jokin funktio päätyy tilanteeseen, josta se ei voi enää jatkaa, siivoaa funktio ensin jälkensä ja sitten poistuu funktiosta "väkivaltaisesti" throw -komennolla. throw- komennossa voi olla parametrina jokin luokka, jolloin suoritus siirtyy kutsuhierarkiassa sille tasolle, jossa on ilmoitettu käsittelijä kyseiselle virheelle. Virheen käsittelyyn ilmoittaudutaan halukkaaksi try - catch parilla. catchin tulee olla heti try-lohkon jälkeen:

cpp\ansicpp\throw0.cpp - yksinkertainen try-catch -esimerkki

	// throw0.cpp
	
	#include <iostream.h>
	
	int main(void)
	{
	  int i;  double x;
	
	  cout << "Anna kokonaisluku >"; cin >> i;
	
	  try {
	    if ( i == 0 ) throw int();
	    x = 1.0/i; cout << x << endl;
	  }
	  catch ( ... ) {
	    cout << "Nollalla jako?" << endl;
	    return 0;
	  }
	
	  cout << "Täällä ollaan onnellisesti!" << endl;
	  return 0;
	}
Erityisen käyttökelpoinen try-lohko on matemaattisten funktioiden tapauksessa, koska jos funktioista tehtäisiin jonkin virhekoodin palauttavia, tulisi itse lausekkeesta varsin sotkuinen, eli käytännössä operaattoreiden lisämäärittelemisestä (operator overloading) ei tulisi mitään. Seuraavana alkeellinen sovellus edelliselle esimerkille (... tarkoittaa että otetaan kaikki virheet vastaan ja on tällä kertaa kielen rakennetta):

cpp\ansicpp\throw1.cpp - kutsun puolella ei enää tarvita if-lauseita

	// throw1.cpp
	
	#include <iostream.h>
	
	//--- Funktio, joka aiheuttaa virheen: ----------------------------------
	double inv(int i)
	{
	  if ( i == 0 ) throw int();
	  return 1.0/i;
	}
	
	int main(void)
	{
	  double x;
	  try {
	    x = inv(-1); cout << x << endl;
	    x = inv(0);  cout << x << endl;
	    x = inv(1);  cout << x << endl;
	  }
	  catch ( ... ) {
	    cout << "Nollalla jako?" << endl;
	    return 0;
	  }
	  cout << "Täällä ollaan onnellisesti!" << endl;
	  return 0;
	}
Itse asiassa throw "heittää" olion ja tämä olio voidaan alustaa "heittämisen yhteydessä", jolloin oliolla voidaan tuoda tietoa siitä, mistä virheestä oli kyse:

cpp\ansicpp\throw.cpp - virhepaluu useamman tason yli

	// throw.cpp
	
	#include <iostream.h>
	#include <cstring.h>
	
	//--- Virheluokat: ------------------------------------------------------
	class cVirhe{
	  int err_n;
	  string err_msg;
	 public:
	  cVirhe(int i=0,char *s=""):err_n(i),err_msg(s){};
	  int n() { return err_n; }
	  const string &err() const { return err_msg; }
	};
	
	class cNollallaJako: public cVirhe {};
	
	class cNegatiivinen: public cVirhe {
	 public: cNegatiivinen(int i=-1,char *s=""):cVirhe(i,s) {};
	};
	
	class cLiianIso: public cVirhe {
	 public: cLiianIso(int i=10,char *s=""):cVirhe(i,s){}
	};
	
	
	//--- Funktio, joka aiheuttaa virheen: ----------------------------------
	double inv(int i)
	{
	  if ( i < -1 ) throw cNegatiivinen(i,"ja pahasti");
	  if ( i <  0 ) throw cNegatiivinen();
	  if ( i == 0 ) throw cNollallaJako();
	  if ( i >  2 ) throw cLiianIso(i,"ja iso");
	  double x = 1.0/i;
	  cout << "i = " << i << " x = " << x  << endl;
	  return x;
	}
	
	int laske(void)
	{
	  for (int i=-2; i<4; i++) {
	    try {
	      double x;
	      x = inv(i); (void)x;
	    }
	    catch ( cNollallaJako ) {
	      cout << "Tulipa jaettua nollalla!" << endl;
	    }
	    catch ( cNegatiivinen Neg) {
	      cout << "Tulipa negatiivinen luku: "
	           << Neg.n() << " " << Neg.err() << endl;
	    }
	  }
	  cout << "Täällä ollaan onnellisesti!" << endl;
	  return 0;
	
	}
	
	
	int main(void)
	{
	  try {
	    laske();
	  }
	  catch ( cVirhe Err ) {
	    cout << "Tänne loput viat (" << Err.n() << "," << Err.err() << ")!" << endl;
	  }
	  catch ( ... ) {
	    cout << "Ja tänne sitten vielä jämät!" << endl;
	  }
	  return 0;
	}
Seuraavana ohjelman tulostus:
	Tulipa negatiivinen luku: -2 ja pahasti
	Tulipa negatiivinen luku: -1
	Tulipa jaettua nollalla!
	i = 1 x = 1
	i = 2 x = 0.5
	Tänne loput viat (3, ja iso)!

Tehtävä 1.37 Virhekäsittely throw:n avulla

Kirjoita "Rakenteiden purkaminen hajottajan avulla" - tehtävä uudelleen käyttäen throw poistumista.


Prev Next Up Title Contents Index