سؤال

هذا السؤال لديه بالفعل إجابة هنا:

  try {
        int* p = 0;
        *p = 1;
    } catch (...) {
        cout << "null pointer." << endl;
    }

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

هل كانت مفيدة؟

المحلول

لا يوجد شيء مثل "استثناء المؤشر الفارغ" في C++.الاستثناءات الوحيدة التي يمكنك التقاطها هي الاستثناءات التي تم طرحها بشكل صريح throw التعبيرات (بالإضافة إلى ذلك، كما أشار بافيل، تم طرح بعض استثناءات C++ القياسية بشكل جوهري بواسطة المعيار operator new, dynamic_cast إلخ).لا توجد استثناءات أخرى في C++.إلغاء الإشارة إلى المؤشرات الفارغة والقسمة على صفر وما إلى ذلك.لا يولد استثناءات في C++، فإنه ينتج سلوك غير محدد.إذا كنت تريد طرح استثناءات في مثل هذه الحالات، فمن مسؤوليتك اكتشاف هذه الشروط يدويًا والقيام بها throw صراحة.هذه هي الطريقة التي تعمل في C++.

أي شيء آخر يبدو أنك تبحث عنه له علاقة بلغة C++، ولكنه بالأحرى ميزة لتطبيق معين.في Visual C++، على سبيل المثال، يمكن "تحويل" استثناءات النظام/الأجهزة إلى استثناءات C++، ولكن هناك سعرًا مرتبطًا بهذه الوظيفة غير القياسية، والتي لا تستحق الدفع عادةً.

نصائح أخرى

انت لا تستطيع.يعد إلغاء الإشارة إلى مؤشر فارغ أمرًا في النظام.

في Linux، يقوم نظام التشغيل بإصدار إشارات في تطبيقك.نلقي نظرة على com.csignal لمعرفة كيفية التعامل مع الإشارات."للالتقاط" واحدة، يمكنك ربط وظيفة سيتم استدعاؤها في حالة SIGSEGV.هنا يمكنك محاولة طباعة بعض المعلومات قبل إنهاء البرنامج بأمان.

يستخدم ويندوز معالجة الاستثناءات المنظمة.يمكنك استخدام instristics __try/__except, ، كما هو موضح في الرابط السابق.الطريقة التي قمت بها في أداة تصحيح أخطاء معينة كتبتها كانت باستخدام الوظيفة _set_se_translator (لأنه يتطابق بشكل وثيق مع الخطافات).في Visual Studio، تأكد من تمكين SEH.باستخدام هذه الوظيفة، يمكنك ربط وظيفة لاستدعائها عندما يثير النظام استثناءً في تطبيقك؛في حالتك سوف نسميها مع EXCEPTION_ACCESS_VIOLATION.يمكنك بعد ذلك طرح استثناء ونشره مرة أخرى كما لو تم طرح استثناء في المقام الأول.

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

هناك طريقة سهلة للغاية لالتقاط أي نوع من الاستثناءات (القسمة على صفر، انتهاك الوصول، وما إلى ذلك) في استوديو مرئي استخدام try -> catch (...) كتل.

التغيير والتبديل البسيط في المشروع يكفي.فقط قم بتمكين /EHa الخيار في إعدادات المشروع.يرى خصائص المشروع -> C/C++ -> إنشاء التعليمات البرمجية -> تعديل تمكين استثناءات C++ إلى "نعم مع استثناءات SEH".هذا كل شيء!

انظر التفاصيل هنا:http://msdn.microsoft.com/en-us/library/1deeycx5(v=vs.80).aspx

لا يقوم C++ بفحص المؤشر (على الرغم من أنني أفترض أن بعض التطبيقات يمكنها ذلك).إذا حاولت الكتابة إلى مؤشر فارغ، فمن المرجح أن يتعطل بشدة.لن يرمي استثناء.إذا كنت تريد التقاط هذا، فأنت بحاجة إلى التحقق من قيمة المؤشر بنفسك قبل أن تحاول الكتابة عليه.

عموما لا يمكنك ذلك.حتى لو تمكنت من ذلك، فسيكون الأمر أشبه بمحاولة وضع ضمادة على غواصة أحدثت تسربًا.

يمكن أن يؤدي التطبيق المعطل إلى ضرر أكبر بكثير من التطبيق الذي تعطل.نصيحتي هنا هي السماح له بالتعطل ثم إصلاح سبب تعطله.شطف.يكرر.

كما قال الآخرون، لا يمكنك القيام بذلك في C++.

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

لا توجد طريقة مستقلة عن النظام الأساسي للقيام بذلك.ضمن Windows/MSVC++ يمكنك استخدامه __يحاول/__يستثني

لكنني لا أوصي بالقيام بذلك على أي حال.من المؤكد أنك لا تستطيع التعافي بشكل صحيح من خطأ التجزئة.

إذا أردت ذلك، يمكنك فقط التحقق من المؤشر بنفسك ورمي ...

if (p == nullptr) throw std::exception("woot! a nullptr!")
p->foo();

لذلك بالطبع سيكون هذا فقط لتصحيح المشكلة، ولا ينبغي أن يحدث nullptr في المقام الأول :)

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

إجابة طويلة - يمكنك أن تفعل أكثر مما قد تعتقد، وبالتأكيد أكثر من مجرد تعطل البرنامج الافتراضي.ومع ذلك، عليك أن تضع في اعتبارك 3 أشياء:
1) هذه الأخطاء أكثر خطورة من الاستثناءات وغالبًا لا يمكن تقديمها كاستثناءات لمنطقك.
2) سيعتمد اكتشافك ومعالجة المكتبة لها على النظام الأساسي في النهاية الخلفية، على الرغم من أنه يمكنك توفير واجهة مجردة نظيفة للاستهلاك العام.
3) ستكون هناك دائمًا بعض الأعطال السيئة جدًا بحيث لا يمكنك حتى اكتشافها قبل النهاية.

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

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

في VC++ 2013 (والإصدارات السابقة أيضًا) يمكنك وضع نقاط التوقف على الاستثناءات:

  1. اضغط على Ctrl + Alt + حذف (سيؤدي هذا إلى فتح مربع حوار الاستثناء).
  2. قم بتوسيع "استثناءات Win32"
  3. تأكد من تحديد استثناء "انتهاك الوصول 0xC0000005".

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

لا يوجد استثناء لمؤشر NULL في c++ ولكنك لا تزال ترغب في التقاط نفس الشيء، فأنت بحاجة إلى توفير تطبيق الفصل الخاص بك لنفسه.

أدناه هو المثال لنفسه.

class Exception {

public:
   Exception(const string& msg,int val) : msg_(msg),e(val) {}
  ~Exception( ) {}

   string getMessage( ) const {return(msg_);}
   int what(){ return e;}
private:
   string msg_;
   int e;
};

الآن استنادًا إلى فحص المؤشر NULL، يمكن طرحه مثل، throw(Exception("NullPointerException",NULL));وفيما يلي رمز لالتقاط نفسه.

 catch(Exception& e) {
      cout << "Not a valid object: " << e.getMessage( )<< ": ";

        cout<<"value="<<e.what()<< endl;
   }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top