الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

التعامل المنظم مع الاستثناءات

بدأه garo في 19 أبريل 2008 · 5 رد · 2,405 مشاهدة · في المواضيع والدروس
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

الكثير من المبرمجين لا يعير الاستثناءات أي اعتبار وهذا ما يجعل البرنامج غير سليم وهو ما يودي ألي توقف البرنامج عادة.

الاستثنائات هي عبارة عن أخطاء غالبا غير مقصودة تحدث عند التعامل مع احدي مكونات الكمبيوتر برمجيا وذلك

بفشل هذا المكون في تنفيذ الأمر المطلوب منه.

متى تحدث الاستثناءات؟

تحدث الاستثنائات عندما يطلب البرنامج التعامل مع احدي أجهزة الداخلية للكمبيوتر مثل الذاكرة ،المعالج، الفيديو، القرص،الخ

ويعتبر القسمة علي صفر هي من أشهر الاستثناءات وذلك لان المعالج لا يستطيع تنفيذ هذا الأمر، كذلك عند فشل محرك الأقراص

في فتح ملف أو الكتابة والقرءاة منه الخ.

كيف يتم التعامل مع الاستثناء؟

تتيح لغة C++ طريقة للتحكم في الاستثناءات بكل يسر فهنالك كلمتين محجوزتين للتعامل مع الاستثناءات وهي

الكلمة try والكلمة catch ،يجب وضع الأوامر التي تتعامل مع احدي المكونات داخل المقطع try.

مثلا:

Try
{
//code
File.open(szFile);

}
Catch(...)
{
Msg(“error cant open file”)
}

المثال السابق يوضح الطريق التي يمكن استخدامها لحماية البرنامج من فشل القرص في فتح الملف بوضع الاوامر

التي تتعامل مع الملف داخل عبارة try ووضع الاوامر التي تتعامل مع الاستثناء داخل عبارة catch. عند فشل القرص

يحدث استثناء ويتم القفز ألي داخل عبارة catch لتنفيذ الاوامر التي بداخلها. المثال السابق يعرض رسالة خطاء

للمستخدم فقط ولكن يمكنك إضافة أشياء أخري مثل إغلاق الملف أو تسجيل هذا الاستثناء داخل ملف Log يستخدمه

البرنامج لتحسين البرنامج مستقبلا.

حاول دائما حماية البرنامج من الأوامر التي تتعامل مع مكونات الحاسوب بوضعها داخل عبارات try و catch ،لكن لا تكثر

من استخدام try حاول بقدر الإمكان حماية المناطق التي تشك فيها فالإكثار من استخدام try يجعل البرنامج اكبر حجما.

تعشيش العبارة catch.

يمكن تعشيش عبارة catch عدة مرات مع عبارة try واحدة .

try
{
}
catch(FileNotFound)
{
}
catch(FileOpenError)
{
}
catch(...)
{
}

المثال السابق يتعامل مع مجموعة من الاستثنئاءات بتعشيش عدة عبارات catch ، حيث يعتبر FileNotFound استثناء

و FileOpenError استثناء،

طريقة عمل المثال السابق هي أن يتم تنفيذ الأوامر داخل عبارة try وإذا حدث استثناء يتم القفز ألي عبارة catch الأولي

ويتم مقارنة الاستثناء بكائن الاستثناء FileNotFound أذا تطابق يتم تنفيذ الكود داخل عبارة catch هذا وإذا لم يتطابق

يتم مقارنة الاستثناء بالكائن الأخر الذي يله وهكذا. عند وضع ثلاث نقاط بدل كائن الاستثناء فهذا يعني أي نوع من كائن الاستثناءات.

أنشاء هيكل للاستثناءات.

من أفضل الطرق لحماية البرنامج كاملا هي أنشاء هيكل ثابت للاستثناءات ،لقد ذكرنا في المثال السابق كائن الاستثناء، لا تشغل

بالك كثيرا فهو عبارة عن طبقة من إنشائك لا غير، هذه الطبقة قد تكون جزء من عدة طبقات فلكل استثناء طبقة خاصة به .

class exp_base
{
Protected:
char msg[1024];
unsigned int err_n;
}

class exp_file: public exp_base
{
exp_file (char* errmsg,int err)
{
msg = errmsg;
err_num = err;
}
}

class file
{
public:
int open(char* file_name) throw(exp_file)
{

if( !file_name )
throw file_name (“the file name is empty”, E_NMAE_OF_FILE); 
 return E_NMAE_OF_FILE;
if(file_name == “”)
throw file_name (“the file name is empty”, E_NMAE_OF_FILE);
 return E_NMAE_OF_FILE;

try
{
//open the file
}
catch(...)
{
//catch
}

int err = open(file_name);
if(err != 1) throw(exp_file_not_found);
}
}

بعد أنشاء هيكل للاستثناءات يمكنك التعامل بكل سهولة مع الاستثناءات التي تقع و فعل ما هو مناسب حيالها.

( _ /)

(='.'=)

(")-(")

#2

ماشاء الله عليك يا garo مبدع كعادتك ,

ايوا كذا خلي القسم يشعشع , :D

خلينا ننتقل إلى الدروس ونتعلم بدال حل الواجبات :wub:

بشأن الاستثناءات انا قاعد اعد درس عن الاستثناءات قسمته إلى ثلاثة اقسام : ( التعامل الحر - التعامل مع الكائنات - الاخفاقات المشهورة مثل new )

ان شاء الله قريبا اعرضه

بشأن الدرس :

رائع جدا بمعنى الكلمة , وتستحق الشكر عليه ,

, يشرفني بأن اكون اول من يرد على هذا الموضوع :D

تم تعديل هذه المشاركة بواسطة time1 في 19 أبريل 2008 في 12:17

llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#3

بارك الله فيك أخي garo .

أحب ان أضيف أيضا انه لعمل تجاوز لأي استثناء يمكن استخدام :

__try
{
	//Code which may raise exception
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
	//Inform user about error
}

عند حدوث أي استثناء يتم الانتقال مباشرة الى هذا الكود تحت except , مثلا :

__try
{
	a = 50;
	b = 30;
	c = 0;
	d = (a*b)/c;
	a = 0;
	b = 1;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
	printf("Exception accured !");
}

عند

d = (a*b)/c

يحدث خطأ وهو القسمة على صفر وبذلك لا يتم تنفيذ الجزء الذي يليه :a = 0 و b = 1 .

ماذا لو اردنا كتابة كود كالتالي :

void ReadMemory()
{
	void *mem = malloc(500);
	memcpy(mem, (void*)0xF7886611, 500);
	free(mem);
}

من الواضح جدا ان هناك استثناء سيحدث عند الدالة memcpy حيث نقوم بنسخ من عنوان خارج الـuser-space وربما أيضا لا وجود له , حسنا سنقوم بالتالي :

void ReadMemory()
{
	__try
	{
		void *mem = malloc(500);
		memcpy(mem, (void*)0xF7886611, 500);
		free(mem);
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
		printf("Error while reading !");
	}
}

هذا الكود سيقوم بتجاوز الخطأ واستكمال البرنامج أي سيمنع حدوث crash , لكن هذا الكود خطأ 100% , السبب : عند حدوث الاستثناء في memcpy سيتم الانتقال تلقائيا الى printf ولن يتم تنفيد free وهذا خطأ غير مغفور بالذات اذا كان برنامجك كبير و يستهلك حجم كبير من الذاكرة , حسنا لتصحيح هذا الخطأ سنقوم بالتالي :

void ReadMemory()
{
	__try
	{
		__try
		{
			void *mem = malloc(500);
			memcpy(mem, (void*)0xF7886611, 500);
		}
		__finally
		{
			free(mem);
		}
	}
	__except(EXCEPTION_EXECUTE_HANDLER)
	{
		printf("Error while reading !");
	}
}

الكود السابق يستخدم finally وهي تقوم بتنفيذ كود داخلها سواء عند حدوث خطأ او لا وهذه ميزة كبيرة لأن بهذه الطريقة سيتم تحرير الذاكرة عن طريق free سواء حدث استثناء او لا لكن تذكر ان finally وحدها لن تقوم بمتابعة تنفيذ البرنامج لذلك قمنا بتضمينها داخل except .

تم تعديل هذه المشاركة بواسطة GamingMasteR في 19 أبريل 2008 في 14:09

mov eax, dword ptr ds:[0xffdf0308]

jmp dword ptr [eax+0xfc]

#4

بارك الله فيك .

فقط لمزيد من الفائدة .. الاخ سلطان الثبيتي .. كتب أيضا عن هذا الموضوع .

/index.php?showtopic=104400

وهذا لايعني عدم اعادة شرحه مرة اخرى بطريقة اخرى ..

بارك الله فيك أخي garo .. مواضيع قليلة لكن مفيدة :) .

* أنا لدي مشروع حاليا .. وأريد توظيف الاستثناءات .. لا أعلم .. هل أعمل وراثة من exception الموجود في STL ,, أو أن هذا لايفيدني كثيرا .

لا ارى فائدة بعمل وراثة لهذا ال exception .. استطيع ان اعمل عدة كلاسات متوارثة .. تقوم مقام الموجود في STL .. لذا .. هل أطور نظام exception مبني على الموجود في ال STL ؟

تم تعديل هذه المشاركة بواسطة الشمري في 19 أبريل 2008 في 14:25

logo1.png تطبيق طمأنينة ، نسخة بيتا على أندرويد

عبدالله الشمّري - Al-Shammari

CodingAlone.com

twitter @abshammeri

abshammeri AT gmail.com

github : abshammeri

#5

شكرا اخوتي علي المشاركة.

اقتباس
* أنا لدي مشروع حاليا .. وأريد توظيف الاستثناءات .. لا أعلم .. هل أعمل وراثة من exception الموجود في STL ,, أو أن هذا لايفيدني كثيرا .

لا ارى فائدة بعمل وراثة لهذا ال exception .. استطيع ان اعمل عدة كلاسات متوارثة .. تقوم مقام الموجود في STL .. لذا .. هل أطور نظام exception مبني على الموجود في ال STL ؟

اخي الشمري يمكنك انشاء هيكل مبني علي STL للاستفادة من المميزات الموجودة به

( _ /)

(='.'=)

(")-(")

#6

السلام عليكــم ورحمـة الله وبركاتــه ،،

up

مواضيع مشابهة