2. BLM225
Nesneye Dayalı Programlama
2
10. İstisna İşleme (Exception Handling)
Bir yazılım geliştirilirken önemli konulardan birisi de ortaya çıkabilecek hataların
yönetilmesidir. Program yazılırken bir syntax(yazım) hatası yapılmış ise programın
derlenmesi sırasında hata kullanıcıya bildirilecektir. Bu tür hataların bulunması ve
düzeltilmesi kolaydır.
Bazı hatalar derleme aşamasında değil, program çalıştırıldığında ortaya çıkarlar. Çalışma
zamanı hataları ise daha çok mantıksal yanlışlıklardan kaynaklanır ve tespiti nispeten daha
zordur. Örneğin kullanıcının girdiği iki sayıyı toplayan bir program yazdığımızı düşünelim.
Kullanıcı sayıların yerine herhangi bir harf girerse programımız çalışma zamanı hatası verir
ve kendisini sonlandırır. Böyle bir durumu engellemek için toplama işlemini yapmadan önce
kullanıcının girdiği veriyi kontrol edip sayı olmayan bir değer girilip girilmediği kontrol
edilebilir. Örneğin Kullanıcı iki sayının bölümü işleminde bölen sayıyı dalgınlıkla sıfır
girmesi durumunda bir sıfırabölme hatası oluşacaktır. Bu hata her zaman karşılaşılan bir hata
değildir. Bir başka örneğimizde dizi işlemleri ile ilgili olsun. 100 elemanlı bir dizi düşünelim.
Bu dizi de çalışma anında kullanıcı 115. Elemana erişmek isterse dizide olmayan bir elemana
erişmek istemiş olacaktır. Bu durum bir bellek hatasına neden olacaktır.
İstisna(Exception) tanımı
İstisna (exception), bir kod dizisinde, çalışma sırasında ortaya çıkan, olağan dışı durumlardır.
Başka bir ifade ile bir çalışma zamanı (run-time) hatasıdır. İstisna işleme (exception handling)
ise, kodu istisnalardan kurtarma işlemidir. İstisnalar, programcılara, hatalar karşısında
istenildiği şekilde davranabilme ve oluşacak hataları kontrol altına alabilme yeteneği ve
esnekliği sağlar. İstisnai durum yakalama mekanizması programımızın bir çalışma zamanı
hatasıyla karşılaştığında hata verip kendini sonlandırması yerine daha farklı işlemler
yapılabilmesini sağlar.
Normal olarak bir sistemi tamamen hatalara karşı korunaklı tasarlamak ve oluşturmak işin
doğası gereği çok zordur. Çünkü çıkabilecek hataların önceden tamamıyla düşünülmesi
mümkün olmamaktadır. Sistemlerin tamamen çökmesinin veya güvenlik problemleriyle
karşılaşmalarının çoğunlukla istisnalardan kaynaklandığı bilinmektedir. Program çalışırken
yaygın olarak ortaya çıkabilecek yazılım ve donanımdan kaynaklanan istisnalar aşağıda
verilmiştir. Bu istisnalar dışında başka istisnaların da olabileceği unutulmamalıdır.
Sıfıra bölme hatası
Tür dönüşüm hatası
Null referance hatası
Limitin dışında kullanılan dizi işlemlerinde,
Aritmetik taşmalarında,
Geçersiz fonksiyon parametrelerinde ve başarısız bellek yönetiminde
Erişilemez bellek alanına okuma veya yazma
Pozitif ve negatif sınır aşımı
veri tutarsızlığı
operatör hatası
bellek hatası
yanlış girdi
donanımsal tutarsızlıklar
çevresel faktörler
bellek yetersizliği,
internet bağlantısının kurulamaması,
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
2
3. BLM225
Nesneye Dayalı Programlama
3
disk problemleri
Bu noktada unutulmaması gereken ilk nokta istisna yönetimi performans açısından pahalı bir
seçenektir. Bu nedenle programcılıkta ilk seçeneğimiz programımıza giriş yapan bütün
değerleri maskeleme, büyüklük ölçümü, tip uyum denetimlerini gibi mekanizmalarla
denetlemektir. Gereksiz yere kullanılacak istisna yönetimi büyük performans kayıplarına
neden olmaktadır.
İstisna yönetiminde kullanılan komutlar
Hataların oluşması durumunda programcıya düşen temel görev programının bu hatalardan
dolayı tamamen çökmesini engellemektir.
Bir istisnayı yakalamak için öncelikle istisnanın ortaya çıkabileceği kod aralığını tespit etmek
gerekir. Bu işlem gerçekleştirildikten sonra aşağıdaki ifadelerden birini kullanarak istisna
yakalama işlemi gerçekleştirilir.
C++’da istisna işlem için kullanılan komutlar şu şekildedir.
-try
-catch
-throw
try bloğu istisnanın oluşabileceği yeri bloklayan kısımdır. catch bloğu ise oluşan istisna ile
ilgilenecek kod parçasının bulunduğu bloktur. İstisna istenildiği takdirde
Temel olarak C++’da ki istisna işlem kalıbı şöyledir:
try
{
//istisnanın oluşabileceği kod parçası
if( koşul-1) throw degisken-1; // herhangi bir değeri atabiliriz.
if( koşul-n) throw degisken-n; // herhangi bir değeri atabiliriz.
}
catch (veritipi1 degisken-1)
{
//istisna işleme kodu
}
.
.
catch (veritipi2 degisken-n)
{
//istisna işleme kodu
}
.
.
catch (...)
{
//istisna işleme kodu
}
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
3
4. BLM225
Nesneye Dayalı Programlama
4
İstisna üretebilecek komutların bulunduğu kısım try bloğu içinde yazılır. Burada hata oluşma
durumunda fırlatılacak değer throw ile belirtilir. Fırlatılacak değer her hangi bir türden
olabilir. İstisna oluşması durumunda ilgili catch bloğu çalıştırılır. İstisna oluşmaması
durumunda programın çalışması catch bloğu altındaki satırlardan devam eder. İstisna
oluşması durumunda programın çalışması catch bloğuna daha sonra catch bloğunun altından
devam eder.
Try komutu
try anahtar sözcüğünden sonra bir blok oluşturmak zorunludur. Buna try bloğu denir. Catch
anahtar sözcüğünden sonra bir blok oluşturulur, buna da catch bloğu denir. Catch bloğu try
bloğundan hemen sonra oluşturulmak zorundadır. Catch bloğu hata oluştuğunda programın
akışının geçirileceği noktayı belirler. try bloğu, hangi bölgede ortaya çıkan hataların ele
alınacağını belirlemekte kullanılır.
Catch komutu
Bir try bloğuna ilişkin birden fazla bir birini takip eden catch bloğu olabilir
Catch bloklarının bir tane parametresi olur. Catch parantezinde yalnızca parametre türü
belirtilebilir, parametre değişkeni adı verilmeyebilir.
catch(int) ; integer gelen her türlü istisnayı yakalar
catch(int e); integer gelen e istisnasını yakalar
catch(...) ; her türlü istisnayı yakalar.
try{
// komutlar
}
catch(int x) { cout << "int istisna"; }
catch(char c) { cout << "char istisna"; }
catch(...) { cout << "varsayılan istisna"; }
Throw komutu
Throw komutu hata oluştuğunda programın akışını catch bloğuna yönlendirmek için kullanılır
Derleyici, throw anahtar sözcüğünün yanındaki ifadenin türünü tesbit eder, bu türe uygun bir
catch bloğu varsa programın akışını o catch bloğuna yönlendirir, yoksa ise programı
sonlandırır. Throw işlemi bir goto işlemi gibidir, yani akış catch bloğuna geçer ve daha sonra
catch bloğunun altından devam eder, geriye dönmez.
int num=5;
string str="Hata var!!!";
throw 4; //Sabit değer 4 fırlatılır.
throw x; //x değişken değeri fırlatılır
throw str; //str değeri fırlatılır.
throw string("Exception found!");
Catch blokları sırası ile ele alınırlar. Aşağıda verilen örnekte bir istisna oluşması durumunda
satır2 ile belirtilen catch bloğu çalışacaktır. Bu blokta her türlü istisna yakalanır. Genel bir
istisna yakalama bloğudur. Bu catch bloğunda hatanın nedenini söyleyemeyiz. Bu yüzden
catch bloklarının sırası önemlidir.
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
4
5. BLM225
Nesneye Dayalı Programlama
5
try //satır1
{
//komutlar
}
catch(...) // satır2
{
// komutlar
}
catch(int x) // satır3
{
// komutlar
}
#include <iostream>
#include <string>
#include <conio.h>
using namespace std;
// exceptions
int main () {
try
{
int a;
int b,c;
a=5.1;
b=0;
// possible errrors
if (b==0)
throw 5;
else
c=a/b;
cout<<c<<endl;
}
catch (int a)
{
cout << "An exception occurred.";
if (a==5)
cout << "zero division error " << endl;
else
cout<<"undefined exception"<<endl;
}
getch();
return 0;
}
#include <iostream>
#include <string>
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
5
6. BLM225
Nesneye Dayalı Programlama
6
#include <conio.h>
using namespace std;
float a,b,c;
// exceptions
int main () {
cout<<"a degeri gir ";
cin>>a;
cout<<"b degeri gir ";
try
{
cin>>b;
// possible errrors
if (b==0)
throw 'a';
else
c=a/b;
cout<<c<<endl;
}
catch (char a)
{
cout << "An exception occurred.";
if (a=='a')
cout << "zero division error " << endl;
else
cout<<"undefined exception"<<endl;
}
getch();
return 0;
}
#include <iostream>
#include <string>
#include <conio.h>
using namespace std;
int a,b,c;
// exceptions
int main () {
try
{
cout<<"a degeri gir ";
cin>>a;
cout<<"b degeri gir ";
cin>>b;
// possible errrors
if (b==0)
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
6
7. BLM225
Nesneye Dayalı Programlama
7
{
throw 'a';
}
else if (b>65536)
{
throw 'c';
}
else
{
c=a/b;
}
cout<<c<<endl;
}
catch (char a)
{
cout << "An exception occurred.";
if (a=='a')
{
cout << "zero division error " << endl;
}
else if (a=='c')
cout << "tasma hatasi" << endl;
else
cout<<"undefined exception"<<endl;
}
getch();
return 0;
}
İç içe try blokları kullanılabilir.
iç içe try blogu
try{
try{
// komutlar
}
catch(int n) {
throw;
}
}
catch(...) {
cout << "istisna olustu";
}
Çeşitli örnekler
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
7
8. BLM225
Nesneye Dayalı Programlama
8
#include <iostream>
using namespace std;
int main () {
try
{
Throw 20;
}
catch(int e)
{
cout << "An exception occurred. "
cout <<"Exception Nr. "<< e << endl;
}
2
#include <iostream.h>
int main()
{
try {
...
char *buffer = new char[size];
if (buffer == 0) throw "Out of memory";
...
}
catch (const char *str) {
cerr << "Exception: " << str << endl;
exit(1);
}
}
3
// A simple exception handling example
#include<iostream>
using namespace std;
int main( ) {
cout<< "Startn";
try{ // start a try block
cout<< "Inside try blockn";
throw 10; // throw an error
cout<< "This will not executen";
}
catch( ...) { // catch an error
cout<< "Bir hata olustun ";
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
8
9. BLM225
Nesneye Dayalı Programlama
9
//cout<< i << "n";
}
cout<< "end";
return 0;
}
4
#include <stdlib.h>
using namespace std;
void Xtest(int test) {
cout << "Inside Xtest, test is: " << test << "n";
if (test) throw test;
}
int main( ) {
cout << "startn";
try { // start a try block
cout << "Inside try blockn";
Xtest (0);
Xtest(1);
Xtest (2);
}
catch (int i) { // catch an error
cout << "Caught one! Number is: "<< i << "n";
}
cout << "endn";
system("pause");
return 0;
}
5
// Throwing an exception from a function outside
// the try block
#include <iostream>
#include <stdlib.h>
//Catches all exceptions
using namespace std;
void Xhandler(int test) {
try {
if (test==0) throw test; // throw int
if (test==1) throw 'a'; // throw char
if (test==2) throw 123.23;// throw double
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
9
10. BLM225
Nesneye Dayalı Programlama
10
}
catch (...) { // catch all exceptions
cout <<"Caught one!n";
}
}
int main( ) {
cout << "startn";
Xhandler(0);
Xhandler(1);
Xhandler (2);
cout << "end";
return 0;
}
6
// Throwing an exception from a function outside
// the try block
#include <iostream>
#include <stdlib.h>
//Catches all exceptions
using namespace std;
void Xhandler(int test) {
try {
if (test==0) throw test; // throw int
if (test==1) throw 'a'; // throw char
if (test==2) throw 3.23;// throw double
}
catch (int x) { // catch all exceptions
cout <<"int turunden bir hata olustu"<<x<<endl;
}
catch (float y) { // catch all exceptions
cout <<"float turunden bir hata olustu"<<y<<endl;
}
catch (...) { // catch all exceptions
cout <<"Caught one!n";
}
}
int main( ) {
cout << "startn";
Xhandler(0);
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
10
11. BLM225
Nesneye Dayalı Programlama
11
Xhandler(1);
Xhandler (2);
cout << "end";
return 0;
}
Throw ifadesi fonksiyon başlığının sonunda kullanıldığında fonksiyon içinde istisnai bir
durum oluşabileceğini ifade eder.
7
// Throwing an exception from a function outside
// the try block
#include <iostream>
#include <stdlib.h>
//Catches all exceptions
using namespace std;
void Xhandler(int test) throw (int, char, double){
if (test==0) throw test; // throw int
if (test==1) throw 'a'; // throw char
if (test==2) throw 3.23;// throw double
}
int main( ) {
cout << "startn";
try {
Xhandler(2);
}
catch (int x) { // catch all exceptions
cout <<"int turunden bir hata olustu"<<x<<endl;
}
catch (char x) { // catch all exceptions
cout <<"char turunden bir hata olustu"<<x<<endl;
}
catch (double x) { // catch all exceptions
cout <<"double turunden bir hata olustu"<<x<<endl;
}
catch (...) { // catch all exceptions
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
11
12. BLM225
Nesneye Dayalı Programlama
12
cout <<"baska bir hata!n";
}
cout << "end";
return 0;
}
İstisnaların Sınflarla ele alınması
İstisnalar bir kategori zincirinde basitçe incelenebilir. C++ standart kütüphanesi, istisna
sınıfları için bir hiyerarşiye sahiptir. Bu hiyerarşi, uygun hata mesajını yazdırmak için her
türetilmiş sınıfta geçersiz hale getirilen what() fonksiyonunu içeren exception temel sınıfıyla
yönetilir.
exception temel sınıfından türetilmiş bazı sınıflara örnek olarak; runtime_eror ve logic_error
(ikisi de, <stdexcept> baslık dosyasında tanımlıdır) verilebilir. Bu sınıflardan türetilmiş bir
çok sınıf daha vardır.
C++ dilinin, özellikleri tarafından fırlatılan, istisnalar da exception’dan türetilmiştir; örneğin,
bad_alloc new tarafından fırlatılır, bad_cast, dynamic_cast tarafından fırlatılır ve
bad_typeid, typeid tarafından fırlatılır. Bir fonksiyonun throw unexpected sonlandırma ya da
set_unexpected ile belirlenmiş başka bir fonksiyonu çağırmak yerine bad_exception
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
12
13. BLM225
Nesneye Dayalı Programlama
13
fırlatılabilir.
logic_error sınıfı, program mantığında genelde uygun kodlar yazılarak düzeltilebilecek
mantık hatalarını belirten bir çok standart istisnanın temel sınıfıdır. Bu sınıflardan bazılarının
tanımları şu şekildedir. invalid_argument sınıfı, bir fonksiyona geçersiz bir argüman
geçirildiğini belirtir. (uygun kodlar yazmak elbette ki geçersiz argümanların fonksiyona
geçirilmesini engeller) length_error sınıfı, yönetilen nesne için belirlenmiş maksimum
boyuttan daha uzun bir uzunluğun kullanıldığını belirtir. out_of_range sınıfı, bir dizi ya da
string için kullanılan belirtecin izin verilen aralık dışında olduğunu belirler.
runtime_error sınıfı bir program yalnızca çalışma zamanında yakalanabilen bir çok hatayı
belirten bir çok sınıfın temel sınıfıdır. over_flow sınıfı, bir aritmetik taşma hatasını belirtir.
under_flow sınıfı, aritmetik sınırdan aşağıya taşma(underflow) hatası oluştuğunu belirtir.
Aşağıda verilen örnekte exception sınıfından kalıtım yolu ile
myexception sınıfı türetilmiştir.
// standard exceptions
#include <iostream>
#include <exception>
using namespace std;
class myexception : public exception
{
virtual const char* what() const throw()
{
return "My exception happened";
}
};
int main () {
myexception myex;
try
{
throw myex;
}
catch(exception& e)
{
cout << e.what() << endl;
}
Return 0;
}
For example, if we use the operator new and the memory
cannot be allocated, an exception of type bad_alloc is
thrown.
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
13
14. BLM225
Nesneye Dayalı Programlama
14
try
{
int* myarray= new int[1000];
}
catch(bad_alloc&)
{
cout << "Error allocating memory."<< endl;
}
// User-defined exception class.
#include <iostream>
#include <string>
using namespace std;
class divisionByZero
{
public:
divisionByZero() {
message = "Division by zero";
}
divisionByZero(string str){
message = str;
}
string what(){
return message;
}
private:
string message;
};
int main()
{
int dividend, divisor, quotient;
try
{
cout << "Line 3: Enter the dividend: ";
cin >> dividend;
cout << endl;
cout << "Line 6: Enter the divisor: ";
cin >> divisor;
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
14
15. BLM225
Nesneye Dayalı Programlama
15
cout << endl;
if(divisor==0) throw divisionByZero();
quotient = dividend / divisor;
cout << "Line 12: Quotient - " << quotient << endl;
}
catch (divisionByZero divByZeroObj)
{
cout << "Line 14: In the divisionByZero "
<<"catch block: "<< divByZeroObj .what () << endl;
}
return 0;
}
http://www.functionx.com/cpp/Lesson18.htm
// typeid, polymorphic class
#include <iostream>
#include <typeinfo>
#include <exception>
#include <string>
#include <conio.h>
using namespace std;
class myexception: public exception
{
virtual const char* what() const throw(){
return "Division by zero";
}
};
class CBase {
virtual void f(){}
};
class CDerived : public CBase {
};
int main () {
myexception myex;
try {
/*
int a=5;
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
15
16. BLM225
Nesneye Dayalı Programlama
16
int b,c;
b=0;
if (b==0)
throw myex;
else
c=a/b;
*/
// CBase* a = new CBase;
//CBase* b = new CDerived;
//cout << "a is: " << typeid(a).name() << 'n';
// cout << "b is: " << typeid(b).name() << 'n';
// cout << "*a is: " << typeid(*a).name() << 'n';
// cout << "*b is: " << typeid(*b).name() << 'n';
//CBase cb1;
//CBase *cb2=&cb1;
//cout << typeid(cb2).name();
//CBase * cb = 0;
//cout << typeid(*cb).name();
// CDerived rd;
//CBase& cbc = dynamic_cast<CBase&>(rd);
// CBase cbc;
// CDerived& rd = dynamic_cast<CDerived&>(cbc);
}
catch (exception& e) {
cout << "Exception: " << e.what() << endl;
}
catch (bad_typeid& bt)
{
cout<< "bad_typeid caught: " << bt.what() << 'n';
}
catch (bad_cast& bc)
{
cout << "bad_cast caught: " << bc.what() << 'n';
}
getch();
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
16
17. BLM225
Nesneye Dayalı Programlama
17
return 0;
}
Karabük Üniversitesi Uzaktan Eğitim Araştırma ve Uygulama Merkezi
Mühendislik Fakültesi No: 215 Balıklarkayası Mevkii 78050 Karabük TÜRKİYE
17