abshammeri

الاستثناءات أو رسائل الأخطاء في محركات الألعاب

قنص الأخطاء في محركات الألعاب .   12 اصوات

  1. 1. ???? ???? ????? ???? ??????? ??????? ?? ???? ??? ???

    • ??????????? Exceptions
      3
    • ????? ??????? Error Message
      3
    • ???? ??? ????????? ( ???? ??? ??? )
      6

من فضلك سجل دخول او سجل حساب جديد قبل التمكن من اضافه صوتك .

25 ردود في هذا الموضوع

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

تم طرح الموضوع أساساّ في مناقشة ، في هذا الموضوع :

http://www.arabteam2000-forum.com/index.ph...t&p=1018751

اقرأ المشاركات رقم ( ابتداءّ من الصفحة السابعة تقريباً ) .

55

59-79

الخلاصة :

- هل نستخدم الاستثناءات أو رسائل الأخطاء في محركات الألعاب وفي محرك الأندلس خصوصاً .

أعلم أن بعض الأخوة ناقش هذا الموضوع .. ولكن لامانع من التوسع فيه أو على الأقل التصويت في أعلى الموضوع حتى نتخذ قرار حاسم .

شخصيا أميل الى الاستثناءات لأنها توفر مرونة عالية في اقتناص الاخطاء :

int func_11()
{

}
int func_1()
{
..
.
.
func_11();
}

int main ()
{
try
{
func_1();

func_2();

func_3();

func_4();
}catch(exception e)
{
printf ( e.what() );
}
}

بينما رسائل الأخطاء .. يجب أن نقوم بفحص الاخطاء بعد كل دالّة حتى لايحصل الخطأ ويغلق البرنامج قبل أن نصطاده :

int func_11()
{

}
int func_1()
{
..
.
.
func_11();

}

int main ()
{
try
{
func_1();
printf ( getLastError() );
func_2();
printf ( getLastError() );
func_3();
printf ( getLastError() );
func_4();
printf ( getLastError() );
}

- من جهة أخرى .. الاستثناءات يقولون أنها بطيئة .. بالتالي رسائل الأخطاء أفضل ؟

- والخيار الثالث .. أن نجمع بين الطريقتين .. لكن كيف وعلى أي أساس .. هنا سنتعب كثيراً في هذا الموضوع .

- أخيرا .. هناك محركات عملاقة مثل Ogre تستخدم الاستثناءات .

- وهناك محركات ممتازة مثل irrlicht تستخدم طرق أخرى غير الاستثناءات .. ( مثل رسائل الاخطاء ) .

تم تعديل بواسطه الشمري
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم

انا ارجح رسائل الأخطاء كى تيسرو على المبرمج معرفت اخطاءه

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

حسناً، سوف أعطي مثال لكيفية استخدام الاستثناءات بطريقة بحيث تقتصر على الأخطاء الكبيرة التي لا يمكن للتطبيق أن يستمر بعدها:

في كود المحرك:

انسخ الكود
  1.  
  2. [color= #0000ff;]void[/color] MainApplicationLoop[color= #000000;]([/color][color= #000000;])[/color]
  3. [color= #000000;]{[/color]
  4. [color= #0000ff;]try[/color]
  5. [color= #000000;]{[/color]
  6. [color= #0000ff;]while[/color][color= #000000;]([/color][color= #ff0000;]1[/color][color= #000000;])[/color]
  7. [color= #000000;]{[/color]
  8. Render[color= #000000;]([/color][color= #000000;])[/color];
  9. Update[color= #000000;]([/color][color= #000000;])[/color];
  10. [color= #007f00;]// Do everything else[/color]
  11. [color= #000000;]}[/color]
  12. [color= #000000;]}[/color]
  13. [color= #0000ff;]catch[/color][color= #000000;]([/color]Exception[color= #000000;]::[/color][color= #808000;]FileNotFound[/color][color= #000000;]&[/color] e[color= #000000;])[/color]
  14. [color= #000000;]{[/color]
  15. Log[color= #000000;]([/color][color= #A31515;]"Fatal error: File not found, ..."[/color][color= #000000;])[/color];
  16. Message[color= #000000;]([/color][color= #A31515;]"Fatal Error"[/color], [color= #A31515;]"File name not found[color= #A31515; font-weight: bold;]n[/color]Information:..."[/color][color= #000000;])[/color];
  17. [color= #000000;]}[/color]
  18. [color= #007f00;]// Other specific exceptions ....[/color]
  19. [color= #0000ff;]catch[/color][color= #000000;]([/color]Exception[color= #000000;]::[/color][color= #808000;]Generic[/color][color= #000000;]&[/color] e[color= #000000;])[/color]
  20. [color= #000000;]{[/color]
  21. Log[color= #000000;]([/color][color= #A31515;]"Generic fatal error: ..."[/color][color= #000000;])[/color];
  22. Message[color= #000000;]([/color][color= #A31515;]"Fatal Error"[/color], [color= #A31515;]"......"[/color][color= #000000;])[/color];
  23. [color= #000000;]}[/color]
  24. [color= #000000;]}[/color]
  25.  
  26. Texture[color= #000000;]::[/color][color= #808000;]Texture[/color][color= #000000;]([/color][color= #0000ff;]const[/color] std[color= #000000;]::[/color][color= #808000;]string[/color][color= #000000;]&[/color] filename[color= #000000;])[/color]
  27. [color= #000000;]{[/color]
  28. [color= #0000ff;]if[/color][color= #000000;]([/color][color= #000000;]![/color]CheckFileExists[color= #000000;]([/color]filename[color= #000000;])[/color][color= #000000;])[/color]
  29. [color= #000000;]{[/color]
  30. [color= #0000ff;]throw[/color] Exception[color= #000000;]::[/color][color= #808000;]FileNotFound[/color][color= #000000;]([/color][color= #A31515;]"filename"[/color][color= #000000;])[/color];
  31. [color= #000000;]}[/color]
  32. [color= #007f00;]// ...[/color]
  33. [color= #000000;]}[/color]
  34.  

في كود التطبيق:

انسخ الكود
  1.  
  2. [color= #0000ff;]void[/color] UserFunction[color= #000000;]([/color][color= #000000;])[/color]
  3. [color= #000000;]{[/color]
  4. Texture Grass[color= #000000;]([/color][color= #A31515;]"grass.jpg"[/color][color= #000000;])[/color]; [color= #007f00;]// Will throw exception if grass.jpg does not exist[/color]
  5. [color= #000000;]}[/color]
  6.  

للأخطاء البسيطة داخل المحرك نستخدم رسائل الخطأ، تلك هي وجهة نظري. :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

نحن بصدد تصميم محرك ثنائي البعد و الاستثناءات لن تؤثر كثيرا و مع ذلك رأي الاخ SandHawk

حل جيد للمشكلة

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
للأخطاء البسيطة داخل المحرك نستخدم رسائل الخطأ، تلك هي وجهة نظري

هل في بالك مثال حاليا على هذه الاخطاء .. فقط لتقريب الصورة .

لأنه المشكلة ستظهر في كل مرحلة .. هل نستخدم رسائل خطأ أم استثناءات .

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم ...

لا أستطيع التخيل كيف تكون رسائل الخطأ أفضل؟

إما أن تجبر مستخدم المحرك على معالجة الأخطاء ضمن منطق برنامجه بواسطة الـ error numbers, أو أن تدعه يكتب منطق البرنامج, و من ثم يضيف الاستثناءات التي يرغب بمعالجتها بعيداً عن منطق اللعبة نفسها.

مثلاً, عملية معينة ربما ينطلق منها exception و لنفرض أنها عملية input/output:

void UserFunction()
{

try
{
.....
.....
..... // do a lot of things here!
.....
.....
}
catch(exception& e)
{
..... // do something in case of ANY exception!
}
}

عندما يريد المستخدم إضافة كود لمعالجة استثناء معين بشكل تفصيلي, مثلاً القيام بمهمة إضافية, أو البحث عن ملف معين, أو أي حالة معينة تستدعي تنفيذ كود إضافي.

فإنه يقوم بإضافة catch جديدة دون المساس بالكود الأصلي الموجود في try:

void UserFunction()
{

try
{
.....
.....
..... // do a lot of things here!
.....
.....
}
catch(stupidException& e)
{
.....
}
catch(smartExeption& e)
{
.....
}
catch(unusualException& e)
{
.....
}
catch(exception& e)
{
..... // do something in case of other exceptions!
}
}

في حالة رسائل الخطأ أو الأرقام, سنبدأ بشيء يشبه التالي:

void UserFunction()
{
.....
.....
..... // do a lot of things here!
.....
.....
}

و ننتهي بشيء يشبه التالي:

void UserFunction()
{
.....
if((stupidError = lastError()) != STUPID_NUMBER)
// do something!
.....
if((SmartError = lastError()) != SMART_NUMBER)
// do something!
.....
if((unuseualError = lastError()) != UNUSEUAL_NUMBER)
// do something!
.....
.....
if(lastError() != NO_ERROR)
// do Something!
}

أعتقد أن البعض غير معتاد على الـ Exceptions في ++C لا أكثر, و الموضوع أسهل مما تتصورون. أنا في الخدمة إذا كان هناك حاجة لشرح أي نقطة.

تحياتي..

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

انا استخدم المزيج بين الإثنين و لكن بإسلوب مختلف عما استخدمه الاخ سلوان.

اولا توجد بعض الأخطاء التى تحدث وقت التشغيل و لا تستطيع التعامل معها بإستخدام try و catch مثل القسمه على الصفر او اى من الاخطاء التى تحدث وقت التشغيل لذا فقد استخدمت اسلوب اخر

اولا قمت بالإستغناء عن الكلمات المحجوزه try و catch و finally و throw و استبدلتهم بـ __try و __except و RaiseException.

قد يقول البعض ان هذا الإسلوب غير عملى حيث انه ليس كل المترجمات تستخدم هذه الكلمات ايضا الداله RaiseException تتبع ويندوز و قد تكون مختلفه داخل اى نظام تشغيل اخر.

الكلام السابق كله صحيح و لكن توجد بعض الأساليب للتغاضى عنه و قبل التطرق إليها دعونا نعود للكلمات السابقه.

للكلمه المحجوزه catch بعض العيوب اهمها هو ان نوع البيانات الذى تستقبله متوقف على الكلمه throw حيث انك اذا استخدمت throw مع char* تستقبل catch النوع char* و إذا كان النوع exception فهى تستقبل exception، و لكن ماذا يحدث فى حالة اخطأ وقت التشغيل فهذا الخطأ لم يتم رميه بإستخدام throw و نحن ايضا لا نعرف ما القيمه التى تم رميها لنستقبلها داخل catch لذا نقوم بإستخدام الثلاث نقاط داخل قوسين catch لتعبر عن اى خطأ، ايضا هذه الفكره غير عمليه لإنها اولا لا تقوم بعمل handling للخطأ ثانيا لا تتوفر لدينا اى معلومات عن الخطأ و بالتالى لن يكون لدينا اى طريقه غير انهاء البرنامج و إن لم تقم بإنهائه بنفسك سيتم انهائه رغما عنك.

الأخطاء التى تحدث وقت التشغيل داخل البرنامج لا يمكن التعامل معها من خلال catch لإنه لم يتم عمل throw لها من داخل البرنامج و حيث انه لم يتم عمل handling لها يتم اعتبار هذا الخطأ unhandled exception لذا يقوم نظام التشغيل بالبحث عن الداله التى من المفترض استخدامها فى هذا النوع من الإستثناءات فعندما لا يجدها يقوم بإستخدام الداله الإفتراضيه و يمرر لها EXCEPTION_EXCUTE_HANDLER و التى تتسبب فى استدعاء الداله SetErrorMode لتظهر لك الشاشه الخاصه بإغلاق البرنامج و التى تحتوى على الزر debug و close فإن اخترت close سيتم اغلاق البرنامج و إن اخترت debug فيتم تشغيل الـ debugger المسجل داخل نظام التشغيل لتقوم بمحاولة حل المشكله بنفسك.

مثال على ما سبق قم بتشغيل البرنامج التالى بترجمه كامله (اى بدون تعقب للأخطاء بإستخدام Ctrl+F5)

انسخ الكود
  1.  
  2. [color= #007f00;]#include <iostream>[/color]
  3. [color= #0000ff;]using[/color] [color= #0000ff;]namespace[/color] std;
  4.  
  5. [color= #0000ff;]void[/color] main[color= #000000;]([/color][color= #000000;])[/color]
  6. [color= #000000;]{[/color]
  7. [color= #0000ff;]try[/color]
  8. [color= #000000;]{[/color]
  9. [color= #0000ff;]int[/color] x[color= #000000;]=[/color][color= #ff0000;]0[/color];
  10. [color= #0000ff;]int[/color] y[color= #000000;]=[/color][color= #ff0000;]5[/color][color= #000000;]/[/color]x;
  11. [color= #000000;]}[/color]
  12. [color= #0000ff;]catch[/color] [color= #000000;]([/color]...[color= #000000;])[/color]
  13. [color= #000000;]{[/color]
  14. cout [color= #000000;]<<[/color] [color= #A31515;]"divide by zero"[/color] [color= #000000;]<<[/color] endl;
  15. [color= #000000;]}[/color]
  16.  
  17. [color= #000000;]}[/color]
  18.  

نأتى الأن للنوع الذى استخدمه و هو الكلمات المحجوزه __try و __except.

قبل ان نكمل لابد ان تعرف ان الإستثناء داخل نظام التشغيل ما هو إلا رقم خطأ و مجموعه من البيانات عن هذا الخطأ و التى يعود بها نظام التشغيل للمستخدم (المبرمج) لتوفر له البيانات التى يحتاجها للتعامل مع هذا الخطأ.

الإسلوب الذى يتم به استخدام try و catch يتم استخدام به __try و __except كالتالى

انسخ الكود
  1.  
  2. [color= #0000ff;]__try[/color]
  3. [color= #000000;]{[/color]
  4. [color= #007f00;]// some code here[/color]
  5. [color= #000000;]}[/color]
  6. [color= #0000ff;]__except[/color][color= #000000;]([/color] [color= #007f00; font-style: italic;]/* condition */[/color] [color= #000000;])[/color]
  7. [color= #000000;]{[/color]
  8. [color= #007f00;]// exception handler[/color]
  9. [color= #000000;]}[/color]
  10.  
  11.  

الفرق الوحيد بين __except و بين catch هو ان الأولى لا تقبل إلا نوع واحد من القيم و هو النوع unsigned int و السبب فى ذلك ان الداله RaiseException التى تستخدم فى إلقاء الإستثناء تطلب رقم الإستثناء (رقم الخطأ) و هذا الرقم هو من نوع DWORD.

توجد بعض الفروق بين try و __try

1 - الأولى تتبع المترجم و الثانيه تتبع نظام التشغيل

2 - الأولى لا تتيح لك التعامل مع اخطاء وقت التشغيل و انما فقط الأخطاء التى تم رميها بإستخدام throw اما الثانيه فتتيح لك التعامل مع اخطاء وقت التشغيل بدون اغلاق البرنامج ايضا تتيح لك التعامل مع اخطأ البرنامج فقط إن كنت قمت برميها بإستخدام RaiseException.

3 - يمكن للـ try الواحده ان تحتوى على اكثر من catch اما __try فلا يمكن ان تحتوى إلا على __except واحده فقط و السبب واضح ان __except لا تقبل إلا نوع واحد فقط اما catch قد تقبل اى نوع.

4 - لابد و ان يوجد اكثر من catch لكل نوع قد يحتمل رميه (لذا نستخدم الوراثه مع الإستثناءات حتى إذا قمت بإستخدام الـ base class فتعنى انك تريد التعامل مع كل الإستثناءات) فإن لن تفعل سيتم انهاء البرنامج بشكل فورى و إن استخدمت الثلاث نقاط فستفقد ميزتان اولهم لا يمكن كتابة try-catch مره اخرى داخل الداله (بعد هذه) لوجود واحده اشمل و تعمل مع كل الأخطاء، ثانيا لن تعرف ماهية الخطأ و هذا يؤدى بك لإغلاق البرنامج لعدم معرفتك بماهية تأثير الخطأ على عمل البرنامج. بالنسبه لـ __try و __except فهى تستقبل نوع واحد فقط و هو رقم و هذه ميزه فدائما انت تعرف ان القيمه المستقبله هى رقم لذا قد تقوم بتصميم مجموعه من ارقام الأخطاء التى قد تنتج عن البرنامج بالإضافة لوجود مجموعة الأخطاء الخاصه بالـ Hardware و عندما يحدث خطأ كل ما تحتاجه هو مقارنة الأرقام التى صنعتها مع رقم الخطأ و الذى يتم احضاره من الداله GetExceptionCode و فى هذه الحاله نستطيع تنفيذ الكود الذى يتلائم مع هذه الحاله و فى حالة اخطأ الـ hardware يمكنك تصميم مجموعة من الدوال العامه بالبرنامج لكل خطأ منهم و تقوم بإستدعائهم و فقا لحدوث الخطأ.

التالى هو نفس المثال السابق و لكن بإستخدام __try

انسخ الكود
  1.  
  2. [color= #007f00;]#include <iostream>[/color]
  3. [color= #007f00;]#include <Windows.h>[/color]
  4. [color= #0000ff;]using[/color] [color= #0000ff;]namespace[/color] std;
  5.  
  6.  
  7. [color= #0000ff;]void[/color] main[color= #000000;]([/color][color= #000000;])[/color]
  8. [color= #000000;]{[/color]
  9. _try
  10. [color= #000000;]{[/color]
  11. [color= #0000ff;]int[/color] x[color= #000000;]=[/color][color= #ff0000;]0[/color];
  12. [color= #0000ff;]int[/color] y[color= #000000;]=[/color][color= #ff0000;]5[/color][color= #000000;]/[/color]x;
  13. [color= #000000;]}[/color]
  14. _except[color= #000000;]([/color]_exception_code[color= #000000;]([/color][color= #000000;])[/color] [color= #000000;]==[/color] EXCEPTION_INT_DIVIDE_BY_ZERO[color= #000000;])[/color]
  15. [color= #000000;]{[/color]
  16. cout [color= #000000;]<<[/color] [color= #A31515;]"integer divide by zero.n"[/color];
  17. [color= #000000;]}[/color]
  18.  
  19. cout [color= #000000;]<<[/color] [color= #A31515;]"this message will mean application continued to execute.n"[/color];
  20. [color= #000000;]}[/color]
  21.  

الأن نعود للسؤال الذى قمت بوضعه بالأعلى

هذا الإسلوب غير عملى حيث انه ليس كل المترجمات تستخدم هذه الكلمات ايضا الداله RaiseException تتبع ويندوز و قد تكون مختلفه داخل اى نظام تشغيل اخر

يمكن تصميم فئه تقوم بعمل encapsulate للدوال الـ Exception الخاصه بنظام التشغيل نقوم بعمل مجموعه من الماكرو و التى نقوم بإستخدامها بدلا من __try و __except و ايضا RaiseException و بالتالى عند الانتقال لنظام تشغيل اخر لن توجد مشكله فى تغيير قيمة الماكرو ليتأثر بها البرنامج ككل.

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

و الله ولى التوفيق

تم تعديل بواسطه Muhammad alaa
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم ...

أخ محمد لماذا تريد استخدام ميزات في ++C في غير محلها, أنت كل ما تريده هو exception hierarchy مبنى على الـ standard exception لا أكثر و لا أقل :)

هذه الصفحة تحتوي على الـ Standard Exceptions بأنواعها:

http://www.cplusplus.com/reference/std/stdexcept/

قم باستخدامها, إذا كان هناك استثناءات متخصصة أكثر قم بالوراثة منها حسب الحاجة, و إذا رأيت أنها لا تغطي جميع الاحتمالات لديك, قم بالوراثة مباشرة من std::exception و من ثم استخدامه في catch كأداة لالتقاط الاستثناءات التي لا تريد التعامل معها في الوقت الراهن.

لماذا تريد عمل throw لـ int أو غيره؟ أليس من المفروض أن يكون الاستثناء كائناً يعبر عن الخطأ و يحمل معلوماته؟

تحياتي...

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

اخى خالد سؤال بسيط ارجو ان تجيبنى عليه هل يمكن اقتناص الـ Hardware Exception بإستخدام فئات الإستثناءات الموجوده داخل الـ cpp.

حاول قنص هذا الخطأ من داخل الـ CPP علما بأنه Hardware Exception و هو EXCEPTION_INT_DIVIDE_BY_ZERO

انسخ الكود
  1.  
  2. [color= #007f00;]#include <iostream>[/color]
  3. [color= #0000ff;]using[/color] [color= #0000ff;]namespace[/color] std;
  4.  
  5. [color= #0000ff;]void[/color] main[color= #000000;]([/color][color= #000000;])[/color]
  6. [color= #000000;]{[/color]
  7. [color= #0000ff;]try[/color]
  8. [color= #000000;]{[/color]
  9. [color= #0000ff;]int[/color] x[color= #000000;]=[/color][color= #ff0000;]0[/color];
  10. [color= #0000ff;]int[/color] y[color= #000000;]=[/color][color= #ff0000;]5[/color][color= #000000;]/[/color]x;
  11. [color= #000000;]}[/color]
  12. [color= #0000ff;]catch[/color] [color= #000000;]([/color]...[color= #000000;])[/color]
  13. [color= #000000;]{[/color]
  14. cout [color= #000000;]<<[/color] [color= #A31515;]"divide by zero"[/color] [color= #000000;]<<[/color] endl;
  15. [color= #000000;]}[/color]
  16. [color= #000000;]}[/color]
  17.  

و الله ولى التوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم أخ محمد,

حاول قنص هذا الخطأ من داخل الـ CPP علما بأنه Hardware Exception و هو EXCEPTION_INT_DIVIDE_BY_ZERO

هل رأيت من قبل مكتبة تقوم بعمل throw في حالة القسمة على صفر؟

أولاً, القسمة على صفر, هو خطأ منطقي يحصل في المعالج. من الطبيعي أن يقوم نظام التشغيل بإيقاف عمل البرنامج في تلك الحالة, إلا إن أردت استخدام أدواته لتفادي هذا الخطأ.

ليس من مهمة مكتبتك, معرفة إذا ما كان المبرمج يقسم على صفر أم لا, و لا من مهمة ++C أو أي لغة أخرى, في Java و NET. يتم هذا الأمر عن طريق الـ framework بينما في ++C يتم من خلال الـ environment التي يعمل فيها البرنامج. لاحظ أن الـ framework يماثل نظام التشغيل في حالة ++C. جرب القسمة على صفر في أي نظام, و ستجد البرنامج توقف عن العمل.

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

لاحظ أن هذا النوع من الأخطاء ليس استثاءً حقيقياً, لأن المفروض أن مبرمج اللعبة, يعود و ينظر إلى الكود الخاطئ الذي قام بكتابته, و يقوم بتصحيحه. أي أن الاستثناء ليس كوداً طبيعياً كعدم وجود ملف على سبيل المثال,

و إنما خطأ في الكود نفسه يستدعي تعديل الكود.

في عالم الـ managed code, هذا يسمى unchecked exception, و في عالم ++C/C تسمى: الأخطاء التي يتم اكتشافها وقت الـ debugging و يقوم المبرمج بتعديل الكود الخاطئ :lol:

تحياتي...

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

أخ محمد,

خذ هذا المثال أيضاً,

عندما تقوم بمحاولة الوصول إلى ذاكرة لا تملكها, خارج حدود مصفوفة مثلاً, مالذي يحصل؟

في Java سيتم رمي استثناء, و في ++C إذا كنت تعمل في الـ debugging سيتم رمي استثناء أيضاً,

هل هذا معناه أنه يجب عليك معالجة هذا الاستثناء؟

رغم أننا أطلقنا على الأمر السابق استثناء, و لكنه مختلف عن مفهوم الاستثناءات الذي نتكلم عنه. ماحصل هو خطأ في الكود يجب تعديله بحيث لا يقوم الكود بالوصول إلى ما لا يملك.

و هذا نفس ما يحصل في القسمة على الصفر, ليس استثناءاً هو خطأ منطقي في الكود.

تحياتي...

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

@ محمد علاء : يبدو أني أخيراً فهمت ما تقصد بالـفرق بين try و __try معلومة جديدة .. شكراً لك .

بالنسبة للأخطاء النابعة من النظام والتي هي عبارة عن أرقام كما تفضلت مثل EXCEPTION_INT_DIVIDE_BY_ZERO ، رأيي من راي الاخ خالد ، هذه خارج نطاق المحرك ، لأن الخطأ ليس ناتج بسبب المحرك ، لذلك تترك عملية اصطياد الخطأ للمستخدم النهائي . يكون المحرك مسؤول عن اصطياد أستثناءات عبارة عن Objects والتي تم عمل لها throw من خلال المحرك نفسه ، مثل :

FileNotFoundException

InternalException

الخ ...

حالياً أرغب في معرفة نوعية الاخطاء التي ذكرها الاخ سلوان هنا :

للأخطاء البسيطة داخل المحرك نستخدم رسائل الخطأ، تلك هي وجهة نظري

وأنواع أخرى من الاخطاء مشابهة للتي ذكرها الاخ محمد علاء مثل : EXCEPTION_INT_DIVIDE_BY_ZERO في Win32 APIs ..

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

بعد أن أفهم هذه النقطة سأصوت :D

تم تعديل بواسطه الشمري
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

يتم تضمين الإستثناءات داخل لغات البرمجه بطريقتين اولهم حدوث الإستثناء ثم رميه للمستخدم حتى يقوم بعمل Handling له و لغات البرمجه التى تتبع هذا المنطق هى جميع المترجمات المبنيه لـ Dot Net Framework و للتأكد من ذلك قم بإستدعاء الداله RaiseException من داخل Try و قم بإقتناص اى Exception من داخل Catch فإذا تم اقتناصه فأعلم ان هذا المترجم يقوم بإقتناص الإستثناءات بعد وقوعها، جرب الكود التالى (VB.Net)

	Private Declare Sub RaiseException Lib "kernel32.dll" (ByVal dwExceptionCode As Integer, ByVal dwExceptionFlags As Integer, ByVal nNumberOfArguments As Integer, ByVal lpArguments() As Object)
Private Const EXCEPTION_INT_DIVIDE_BY_ZERO As Integer = &HC0000094
Private Const EXCEPTION_CONTINUE_EXECUTION As Integer = -1

Sub Main()

Try
RaiseException(EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_CONTINUE_EXECUTION, 0, Nothing)
Catch ex As DivideByZeroException
MsgBox("exception")
End Try

End Sub

النوع الثانى و هو الذى يحاكى وقوع الإستثناء فيقوم بالتحقق من اجزاء الكود التى قد تنتج استثناء فإن كانت كذلك يقوم برمى الإستثناء عوضا عن تنفيذ الكود و اغلب المبرمجين الذين يعملوا على لغات برمجه مثل الـ cpp يقوموا بإتباع هذا الإسلوب و لا اعرف إذا كان هناك مترجم معين يقوم بهذه الطريقه ام لا.

نظام التشغيل ويندوز تم تصميالـ C ة الـ C و حيث انها ليست OOP فهذا يعنى انها لا تتعامل مع فئات و لهذا فالإستثناءات داخل نظام التشغيل كلها عباره عن اكواد و يقوم المترجم او الـ Framework التى تأتى مع المترجم بعمل encapsulate لهذه الأرقام داخل فئات، و الدوال الموجوده داخل هذه الفئات تقوم بإستدعاء دوال نظام التشغيل لإحضار وصف لهذا الخطأ و بعض المعلومات عنه.

يوجد نوعين من الإستثناءات اولهم هو Hardware Exception و الذى ينتج من الـ Hardware الموجوده بالجهاز مثل البروسسور مثل Divde By Zero و حيث ان البروسسور هو الذى يقوم بجميع العمليات الحسابيه فهو الذى يقوم برمى هذا الإستثناء و الذى يقتنصه نظام التشغيل و يعرف الموقع الموجود بالذاكره الذى احدثه ثم يقوم بعمل encapsulate لموقعه و بعض المعلومات عنه داخل struct اسمه EXCEPTION_RECORD و الذى يحتوى على بيانات الإستثناء.

النوع الثانى و يسمى Software Exception و هو يتعلق بالأخطاء الخاصه بنظام التشغيل او الأخطاء التى تحدث داخل برنامجك و من امثلة اخطأ نظام التشغيل FileNotFound فأنت تطلب من نظام التشغيل ان يتعامل مع ملف غير موجود و هذا الخطأ ما هو إلا رقم و حتى نتعامل مع هذا الرقم نستخدم الداله GetLastError. و لكن داخل لغة البرمجه او الـ Framework الخاصه بها يتم تغليف هذا الرقم على شكل فئه حتى تستطيع انت التعامل معه بشكل OOP :wink:

داخل نظام التشغيل توجد طريقتين لتعقب الإستثناءات و التعامل معهم و هم:

  1. Frame-based Exception Handling
  2. Vectored Exception Handling

Frame-based Exception Handling

هذا النوع هو شبيه جدا بالموجود بلغات العالية المستوى و هو عن طريق استخدام اى من الكلمات التاليه

  • __try و __except
  • __try و __finally و __leave

بالنسبه لأولى قمت بشرحها بمشاركه بالأعلى و الثانيه عملها شبيه بعمل الأولى و لكن لا مجال لشرحها الان.

Vectored Exception Handling

الإسلوب المتبع لهذا النوع مختلف تماما عن الأخرى حيث انك هنا تقوم بصنع داله للتعامل مع استثناء معين و تقوم بتسجيلها داخل نظام التشغيل بحيث عندما يقع هذا الإستثناء او يتم رميه بإستخدام الداله RaiseException فإن اول ما يتم عمله هو البحث عن الداله التى تم تسجيلها لهذا الخطأ فإن وجدت يتم تنفيذها قبل اى كود اخر و هذا يعنى انه مهما كان المكان الذى وقع فيه هذا الإستثناء هناك كود واحد فقط هو الذى سينفذ و بعدها اى كود اخر داخل البرنامج بدءا من نقطة حدوث هذا الإستثناء.

ايضا هذا الإسلوب ديناميكى جدا فهو يتيح لك حذف الداله التى قمت بتسجيلها فى اى مرحله من مراحل عمل البرنامج و تسجيل اخرى او عدم تسجيل اى واحده.

أخ محمد لماذا تريد استخدام ميزات في ++C في غير محلها, أنت كل ما تريده هو exception hierarchy مبنى على الـ standard exception لا أكثر و لا أقل

اخى خالد الإستثناءات داخل الـ Cpp صممت لأجل الـ Cpp و ما يتبع من اخطاء الـ RunTime الخاصه بالمترجم فقط. و هذا ما ارفضه تماما فالمفترض ان اللغه مرنه لأقصى درجه حيث انها تتيح لك عمل throw لأى شئ و لكن من داخل اللغه و بالتالى و حيث انك تستطيع عمل throw لأى شئ من داخل اللغه فانت تستطيع استقبال هذا الشئ ايا كان من خلال catch.

و لكن عندما نتكلم عن اخطاء تسبب بها البرنامج وقت التشغيل و هذه الأخطاء خارج حدود الـ Cpp و ايضا الـ RunTime الخاصه به فنجد اللغه تقف عاجزه عن فهم ما اصابها. لذا عندما يحدث هذا لماذا لا ابحث عن اى extension للغه و الذى يتيح لى التحكم بتلك الأخطاء حتى ازيد من فاعلية برنامجى.

و حيث ان الإستثناءات بأبسط صوره لها هى عباره عن ErrorCodes لذا امامى طريق من ثلاثه، اما ان اقوم بصنع اسلوب جديد للتعامل مع الأخطاء و اترك الموجود باللغه او ان اضيف إليه او ان اتعامل مع واحد اخر له ميزات الإثنين.

اما الأول فهو صنع نظام تتبع الأخطاء مبنى على الـ Error Codes و حيث انى سأفقد العديد من مزايا اللغه بإستخدامه و لكن لا مفر منه.

اما الثانى فهو استخدام الموجود باللغه مع بقاء عيوبه مثل البطء و حدود قدارته.

اما الثالث فهو ان اقوم بإستخدام الذى يوفره لى نظام التشغيل و هو مزيج بين الإثنين و بهذا فأكون حصلت على مزايا الإثنين و تركت عيوبهما.

بالنسبه لمزايا النوع الأول السرعه فى التنفيذ صغر حجم الكود الذى يعبر عن الخطأ و عيوبه كثرالتحقق من نوع الخطأ (مثل الموجود بالـ VB6) ايضا لا يمكن تنفيذ كود دون الأخر و ايضا لا يمكن ارجاع التفيذ للداله التى استدعت الداله الحاليه (التى يوجد بها الخطأ) بالإضافه إلى هؤلاء لابد من التحقق حدوث الخطأ فى كل مره استخدم كود قد ينتج عنه خطأ و السبب فى ذلك انه لا يوجد مكان محدد موجود به كود تنقيح الأخطاء.

بالنسبه لمزايا النوع الأول فهى كل عيوب النوع الاول و عيوبه البطء فى التنفيذ حيث اذا كان تم تمرير كائن لابد من التحقق من مكانه فى الشجره لمعرفة نوعه و هل هذا الكود يصلح له ام لا ايضا الكائن نفسه له مساحه معينه بالذاكره لابد من حجزها و تحريرها بعد استخدامه (بالإضافه إلى ذلك الكائن exception الموجود باللغه لا يحتوى إلا على what التى تعطى رسالة خطأ فقط بمعنى انها لا تعطى مكان الكود الذى سبب الخطأ او معلومات عن الـ nested exception إذا كانت توجد او رقم السطر الذى حدث فيه الخطأ او .. او ...).

بالنسبه للنوع الثالث فعيوبه هى انه محدود بنظام التشغيل و غير portable و لكن يمكن عمل encapsulate له ليتم تغييرها تبعا لنظام التشغيل و ستكون المشكله قد تم حلها.

بالنسبه لمزاياه فهى ان الـ exception عبارة عن رقم فهذا يعنى انه لن يحجز إلا 4 بايت و هذا يعنى انه اسرع من الموجود باللغه، ثانيا له نظام structured مثل الموجود باللغه و هذا يعنى اننا يمكننا كتابة الكود بنفس الطريقه التى نستخدمها داخل اللغه نفسها. ثالثا يمكن بإستخدام رقم الخطأ احضار وصف لهذا الخطأ و بالتالى قد تصنع فئه واحد يتم تمرير لها رقم الخطأ و هى تعود لك بكل ما تريد من معلومات عن هذا الخطأ.

قم باستخدامها, إذا كان هناك استثناءات متخصصة أكثر قم بالوراثة منها حسب الحاجة, و إذا رأيت أنها لا تغطي جميع الاحتمالات لديك, قم بالوراثة مباشرة من std::exception و من ثم استخدامه في catch كأداة لالتقاط الاستثناءات التي لا تريد التعامل معها في الوقت الراهن.

كلامك سليم، و لكن ماذا يحدث اذا كانت الفئه std::exception نفسها قدراتها محدوده باللغه و لا تعرف كيف تتعامل مع هو خارج اللغه ماذا افعل حينها ؟؟

لماذا تريد عمل throw لـ int أو غيره؟ أليس من المفروض أن يكون الاستثناء كائناً يعبر عن الخطأ و يحمل معلوماته؟

انا لا اريد عمل throw لـ int و لكن نظام التشغيل هو الذى يقوم بعمل throw لهذا الرقم لذا فانا اجعل مستوى تتبع الأخطاء فى برنامجى يستطيع التعامل مع الإستثناءات القادمه من نظام التشغيل حتى لا يحدث انهيار لبرنامجى بسبب وجود Unhandled Exception.

ليس دائما ما يحتوى الإستثناء عن معلومات تعبر عن هذا الخطأ و إلا كانت الفئه std::exception تحتوى على هذه المعلومات و التى هى غير موجوده بإستثناء وصف

و الله ولى التوفيق

تم تعديل بواسطه Muhammad alaa
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

اخى خالد يبدو اننا كنا نكتب المشاركات فى نفس الوقت

يبدو انك فهمت كلامى بشكل خاطئ فأنا عندما تكلمت عن الإستثناءات داخل محركات الألعاب كنت ايضا اتكلم عن الإستثناءات بشكل عام و تكلمى عن القسمه على الصفر فهو مجرد مثال و لكن توجد امثله فعليه تحدث داخل الألعاب و تنهار اللعبه بسببها مثل Access violation error و الذى يعتبر Hradware Exception و لكن لابد من المبرمج ان يقوم بكتابة كود له.

السبب فى ذلك ان الالعاب الكبيره يتم حجز تحميل اغلب ملفاتها داخل الذاكره كذلك يتم حجز store لها ليتم تخزين به قيم الفئات و المتغيرات و لا يتم عمل allocate له لإن عملية حجز الذاكره و تحريرها تأخذ وقت و تؤدى إلى بط فى اللعبه و الذى ينعكس فيما بعد على ادائها (بالطبع يوجد Resource Manager للتعامل مع ادارة الذاكره و غيرها من مصادر اللعبه).

تحدث فى احيان كثيره و بشكل غير متوقع محاولة الدخول على جزء من الذاكره لا يتبع الجزء الفعال من الفئه و بالتالى يعتبر هذا الجزء protected و لهذا يحدث الـ access violation. (اخرهم حدث معى اليوم داخل برنامج phtoshop حتى قمت بتحديثه).

فكما ترى فى حين انه توجد بعض الإستثناءات التى لا داعى من محاولة عمل فئات لها فإنه توجد إستثناءات لابد من وضعها فى الحسبان و للأسف فإنه داخل الـ cpp لا يمكن التعامل مع هذا النوع من الإس%اءE4اءات. النوع المتاح فقط هو الـ Software Exception.

عندما تقوم بمحاولة الوصول إلى ذاكرة لا تملكها, خارج حدود مصفوفة مثلاً, مالذي يحصل؟

عندما تكون لدينا مصفوفه تم انشائها فى وقت الـ runtime ليتم وضع داخلها بيانات ملف قد يحدث احيانا مع وجود معادلات كثيره Hardware Exception و هو EXCEPTION_ARRAY_BOUNDS_EXCEEDED.

و ليس دائما ما يمكن حل مشكله داخل الكود لإنه مع كبر حجم البرنامج قد تحدث اخطأ نادر حدوثها تماما و قت لا تستطيع معرفتها و لهذا السبب عندما اقوم بعمل برنامج اقوم بتضمين نظام logfile لتتبع اخطأ وقت التشغيل حتى استطيع حلها فيما بعد.

و الله ولى التوفيق

تم تعديل بواسطه Muhammad alaa
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

أخ محمد حبة حبة علينا, أنت تتكلم عن قلب المحرك و أنا أتكلم عن واجهته.

أخي أنت دخلت في مواضيع متفرقة, بداية الـ hardware exceptions ليست من مهمتك, هذه مهمة نظام التشغيل.

قبل سنتين كنت أقوم بعمل hard coding لعنوان التعليمة في الـ interrupts vector في ذاكرة 4 mb لمعالج Motorola.

محرك الألعاب ليس مسؤلاً عن هذه الاستثناءات إن صح تسميتها استثناءات :)

كلامك سليم و لكن ماذا يحدث اذا كانت الفئه std::exception نفسها قدراتها محدوده باللغه و لا تعرف كيف تتعامل مع هو خارج اللغه ماذا افعل حينها ؟؟

عندما تقوم بمحاولة فتح ملف مثلاً, و تفشل عملية الفتح, سواء عرفت أن عملية الفتح فشلت من نظام التشغيل أو أي مكتبة أخرى, نقوم برمي استثناء من المحرك إلى المستخدم.

هذا استثناء حصل, و ليس خطأ منطقي في الكود. الأخطاء المنطقية, هي أخطاء في الكود نفسه.

يبدو انك فهمت كلامى بشكل خاطئ فأنا عندما تكلمت عن الإستثناءات داخل محركات الألعاب كنت ايضا اتكلم عن الإستثناءات بشكل عام و تكلمى عن القسمه على الصفر فهو مجرد مثال و لكن توجد امثله فعليه تحدث داخل الألعاب و تنهار اللعبه بسببها مثل Access violation error و الذى يعتبر Hradware Exception و لكن لابد من المبرمج ان يقوم بكتابة كود له.

عندما يحصل Access Violation, ماهو التصرف المناسب لبرنامج يعمل؟

ببساطة, هذا خطأ في الكود يجب عمل debugging و معرفة سبب العلة. و ربما يتم تطبيق patch كما في حالة Photoshop. أي أن البرنامج نفسه غير سليم.

ربما فهمت كلامك بشكل خاطئ قليلاً, و لكن المحرك لا علاقة له إذا قام مستخدمه بكتابة كود يقسم على صفر, أو جذر عدد سالب,..... هذه أخطاء منطقية.

تحياتي

تم تعديل بواسطه Khaled.Alshaya
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

لقد ضغط زرار enter اثناء كتابتى للمشاركه فتم اضافتها غير كامله.

أخ محمد حبة حبة علينا, أنت تتكلم عن قلب المحرك و أنا أتكلم عن واجهته.

ماشى يا سيدى هكتب بالراحه علشان نلحق نتابع سوا بس قبل ما اقول اى حاجه محتاجين نقرب وجهات النظر علشان انا متكلمش فى الشرق و انت بتتكلم فى الغرب

لن اتكلم عن المحركات و لكن ساتكلم عن الإستثناءات و علاقتها بتسريع البرنامج ايا كان.

أخي أنت دخلت في مواضيع متفرقة, بداية الـ hardware exceptions ليست من مهمتك, هذه مهمة نظام التشغيل.

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

فقد يقول احد مستخدمى المحرك ؟ "يعم عبد الله (مدير المشروع) الحقنا المحرك اتسبب فى انهيار البرنامج؟" و وقتها سنقول له ماذا حدث فيبدء فى الشرح و عندما نطبق ما قاله قد لا يحدث شئ و قد يحدث و السبب فى ذلك وجود حالة خاصه جدا سببت فى انهيار البرنامج و لكن عند تعقب هذا الخطأ قد نتسطيع الحصول على بعض المعلومات عن هذا الخطأ قبل ان نطلب من المستخدم بإسلوب Gentle ان يغلق البرنامج.

و حتى نتكلم عن المحرك، سيتم عمل ان شاء الله جزء للتعامل مع الصور مثل تحميلها فى الذاكره لإستخدامها كمكسيات و بالطبع سنحتاج للتعامل مع دوال نظام التشغيل، لذا قد يحدث حينها ان نقوم بتمرير بعض البيانات الخاطئه طبعا بدون قصد لتلك لأحد الدوال التى قد تسبب فى عملية إنهيار البرنامج الذى يستخدمها - لاحظ انا اتكلم عن ان تعقب الـ exception قد يمنع البرنامج من الإنهيار لإنى اعرف ماذا افعل به عند حدوثه او لأسوء الظروف أقوم بجعل المستخدم هو من يغلق البرنامج.

و كمثال عملى على ما اقول داخل الدوت نت يوجد احداث خاصه بالبرنامج منها الحدث UnhandledException و الذى يرسل لك الإستثناء الذى تسبب فى حدوث الإنهيار و ايضا يسألك إذا كنت تريد غلق البرنامج ام لا.

مثال اخر ببرنامج Firefox حيث ان الإصدار الجديد منه 3.5.3 غير ثابت و ينهار كثيرا و فى كل مره ينهار فيها يظهر لى Dialog يعطينى المعلومات التى تسببت فى الإنهيار و ايضا يتيح لى اعادة تشغيل البرنامج مره اخرى بأخر صفحات كانت به.

ملخص ما اريد قوله: حتى و إن كانت الـ Hardware Exception ليست من اختصاصى فهى واردة الحدوث و حيث انها واردة الحدوث فيجب وضعها فى الحسبان لإنها قد تتسبب فى انهيار البرنامج او المحرك او اللعبه او اى شئ اخر و حيث ان الـ cpp لا تستطيع التعامل مع هذا النوع من الأخطاء فبالتالى انا اقوم بعمل encapsulate للبديل داخل برنامجى حتى استطيع التعامل مع هذا النوع من الأخطاء بالإضافه للأخطاء التى اتعامل معها.

و الله ولى التوفيق

تم تعديل بواسطه Muhammad alaa
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

ملخص ما اريد قوله: حتى و إن كانت الـ Hardware Exception ليست من اختصاصى فهى واردة الحدوث و حيث انها واردة الحدوث فيجب وضعها فى الحسبان لإنها قد تتسبب فى انهيار البرنامج او المحرك او اللعبه او اى شئ اخر و حيث ان الـ cpp لا تستطيع التعامل مع هذا النوع من الأخطاء فبالتالى انا اقوم بعمل encapsulate للبديل داخل برنامجى حتى استطيع التعامل مع هذا النوع من الأخطاء بالإضافه للأخطاء التى اتعامل معها.

نعود لنفس النقطة, هذا خطأ في الكود.

تصور أنك تقوم بطلب اسم ملف لفتحه من قبل المستخدم, و عندما حاولت فتحه ظهر أنه غير موجود. يتم الامساك بالاستثناء, و طلب اسم آخر على سبيل المثال.

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

بينما في الحالة التي تتكلم عنها, فالخطأ الحاصل, هو منع نظام التشغيل لك من العبث بالذاكرة بطريقة خاطئة, أي أن العبث بالذاكرة, ليس أمراً مسموحاً به من الأساس.

ببساطة, نعود للكود الذي نقوم بكتابته, ننظر أين الخطأ و نقوم بإصلاح العلة.

هل تترك برنامج فيه Access Violation دون معرفة سبب الخطأ و اصلاحه؟

مترجمات ++C في وضع الـ debugging و لم أقابل مترجم لا يفعل ذلك, تقوم بامساك جميع الأخطاء, و عرضها للمبرمج.

ما تريد القيام به, هو إضافة عمليات تحقق إضافية في قلب المحرك, للتأكد من سلامة عمله, و ليس للتعامل مع المستخدم.

في هذه الحالات, لديك عدة أمور, أولاً الـ debug version من برنامجك تقوم بامساك جميع الأخطاء المنطقية, و عرضها لك.

يمكنك أيضاً الاستعانة بالـ stack traces للقيام بالـ debugging,

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

تحياتي..

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

اتضحت وجهت نظرك

نعود لنفس النقطة, هذا خطأ في الكود.

صحيح

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

هذا ما اريد قوله و لكن يبدو انى لا استطيع التعبير :)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

هذا ما اريد قوله و لكن يبدو انى لا استطيع التعبير

أنا احسن, صرت عايد "خطأ منطقي" عشر مرات, حاسس اني ضيعت على آخر الليل :lol:

عموماً الموضوع كبير و كبير جداً, مثلاً شيء مثل عندما تطلب ذاكرة, و يتضح أنه لايتوفر ذاكرة (عن طريق new مثلاً),

هل هذا exception أو خطأ منطقي؟ لا تستعجل :)

هذا نفس السؤال يسأله Walter Bright و يجيب عليه John Skeet!ناس كبار حبتين :) يعني الموضوع بالفعل شائك قليلاً.

تم تعديل بواسطه Khaled.Alshaya
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
عموماً الموضوع كبير و كبير جداً, مثلاً شيء مثل عندما تطلب ذاكرة, و يتضح أنه لايتوفر ذاكرة (عن طريق new مثلاً),

هل هذا exception أو خطأ منطقي؟ لا تستعجل

اخطاء التعامل مع الذاكره - مثل محاولة حجز مساحة من الذاكره اكبر من الذاكره المتاحه - هى Software Exception لإن من يقوم بإدارة الذاكره عموما و يقوم بحجز المساحه التى تريدها هو نظام التشغيل.

يمكن ايضا القول فى محاولة حجز مساحة من الذاكره هو خطأ منطقى لإنك تستطيع مقارنة المساحه التى تطلبها بالمساحه الموجوده فعليا.

حاسس انى بقول كلام و بناقضه بنفس الوقت :wacko: ، عموما من قال لا اعلم فقد افتى لذا انا أقول لا اعلم.

و الله ولى التوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

لدي تعليقين صغيرين بخصوص النقاش، أولاً إن هذا المحرك لا يستهدف المستخدمين النهائيين، ولكن مطوّرين مثلنا لذلك فإن الـ debugger يقوم بعملية إظهار الأخطاء من نوع قسمة على صفر أو دخول غير مشروع بطريقة أفضل من أي شيء يمكننا عمله.

ثانياً، الإستثناءات في نظري يجب أن يكون لها فائدة فعلية لكي يحسب لها حساب، مثلاً في حالة الملف المفقود فكل ما يحتاج لعمله المستخدم لحل تلك المشكلة إيجاد الملف ونسخه للمكان الذي يتوقعه البرنامج (كم مرة ظهر لك خطأ ملف DLL مفقود وكان حله بتلك البساطة؟) ولكن ما فائدة خطأ دخول غير مشروع بالنسبة للمستخدم النهائي؟ :)

في التوصيات التي إقترحتها كانت النقطة الأولى هي الوقاية خير من العلاج، يمكننا أن نمنع حصول الأخطاء في المحرك من قبيل القسمة على الصفر أو الدخول غير المشروع بخبرتنا وإمكاناتنا وهي ليست عملية صعبة، حينها لا حاجة للتعامل مع تلك الأخطاء أصلاً من جهتنا.

والآن بالنسبة لتقديم مثال عن استخدام رسائل الخطأ، ففي الحقيقة السطر التالي:

if(!CheckFileExists(filename))

يستخدم مبدأ رسالة الخطأ عن طريق قيمة boolean ليعرف إن كان الملف موجود أو لا، في الحقيقة كل ما عملته هو تخليص المستخدم (المطوّر) من استدعاء هذه الدالة بنفسه ومتابعتها والتعامل معها لتسهيل الإستخدام.

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

عذراً إن لم يكن كلامي واضحاً أو غير مترابط حيث إني إكتشفت اليوم إن لدي حساسية من الروبيان (الجمبري) بالطريقة الصعبة ولا زلت أعاني من تبعات ذلك... :eek:

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
إكتشفت اليوم إن لدي حساسية من الروبيان (الجمبري) بالطريقة الصعبة ولا زلت أعاني من تبعات ذلك

الف سلامه عليك اخ سلوان و ان شاء الله تخف بسرعه متقلقش

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

الأمور واضحة الان ، والشكر موصول لكل من شارك :-) ..

عذراً إن لم يكن كلامي واضحاً أو غير مترابط حيث إني إكتشفت اليوم إن لدي حساسية من الروبيان (الجمبري) بالطريقة الصعبة ولا زلت أعاني من تبعات ذلك...

الله يعينك .. :-)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم ...

أنا أتفق مع الأخ سلون في ما قاله, و هذا هو رأيي من البداية :)

لاحظ أن الدالة التي عرضها الأخ سلون, لاتصدر أي أخطاء بنفسها, هذا يسمى predicate. بمعنى آخر, إن كنا نريد معرفة هل يوجد هذا الملف أم لا, فهذا مقصدنا و ليس خطأ جانبي.

أعتقد أنه في البداية, خلطنا بين الأخطاء, و بين الوظائف التي يوفرها المحرك. ببساطة إن كان المحرك سيوفر دوال للتعامل مع شيء, فهذا شيء, الأمر الآخر هو أن يصدر المحرك أخطاء, من وظائفه, بالتالي عملية كعملية الرسم مثلاً, يمكن أن تتعطل لأي مجموعة من الأسباب نريد الوقاية منها في حالة حدوثها, إما نختار إما رسائل الأخطاء أو الاستثناءات.

حتى أوضح مقصدي, خذ هذا المثال البسيط,

لو أن البرنامج الذي يستخدم المحرك, توقف عن العمل بسبب العبث بالذاكرة لأي سبب, و قام النظام بإيقافه عن العمل - كما في رسالة ويندوز الشهيرة! -, هل نستطيع الاحتياط من هكذا أخطاء؟

بالفعل نستطيع, و لكن هناك طريقتان أمامنا,

الطريقة الأولى, أن نعرف سبب الخطأ, و هو مثلاً قراءة من مكان غير مسموح للمحرك القراءة منه, ببساطة dangling pointer. نرجع لأصل السبب نفسه, لايوجد برنامج بالطبع يريد القراءة من أي مكان عشوائي في الذاكرة!

الحالة الأغلب, هي أن عملية حجز الذاكرة التي نريدها فشلت قبل القراءة من ذلك المكان. بمعنى أبسط, قمنا بحجز ذاكرة, و لكن النظام رفض الطلب لعدم وجود كمية كافية أو خلافه, و لم نقم بالفحص هل تمت عملية الحجز أم لا, لكي نبدأ العمل في تلك المنطقة من الذاكرة.

في هذه الحالة, نقوم بمعالجة الاستثناء المنطلق من دالة الحجز, أو و هي أحد أهم ميزات الـ exceptions في جميع لغات البرمجة, نقوم بعملية rethrow!

الطريقة الثانية, هي بأن نستلم الـ exception من نظام التشغيل حول هذه العملية الغير مشروعة, و لكن ماذا بعد ذلك؟ إذا كان النظام يقول لك بأنك قرأت من مكان غير مسموح لك فيه, أين تذهب؟

هذه الشيء لامجال لحله في الأساس لأنه عارض من الخطأ الأساسي و هو عدم اكتمال عملية حجز الذاكرة.

بالمناسبة, إخفاء مثل هذه العوارض يزيد من صعوبة اختبار المحرك بطريقة غير معقولة,

تحياتي...

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
زوار
This topic is now closed to further replies.

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .