سؤال

أنا أقوم بتصميم تسلسل هرمي استثناء في C ++ لمتصفتي. "التسلسل الهرمي" هو 4 فصول مشتقة من STD :: Runtime_error. أود تجنب مشكلة تشريح بالنسبة لفئات الاستثناء، قدمت منشئو النسخ المحمية. ولكن يبدو أن دول مجلس التعاون الخليجي يتطلب استدعاء منشئ النسخ عند إلقاء مثيلاتهم، لذلك يشكو من منشئ النسخ المحمي. Visual C ++ 8.0 يجمع نفس الرمز غرامة. هل هناك أي طريقة محمولة لنزع فتيل مشكلة تشريح لفئات الاستثناءات؟ هل يقول المعيار أي شيء حول ما إذا كان التنفيذ يمكن / يجب أن يتطلب نسخ منشئ للفئة التي سيتم إلقاؤها؟

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

المحلول

أود أن أوضح من تصميم التسلسل الهرمي استثناء متميزا بمكتبتك. استخدم ال std::exception التسلسل الهرمي قدر الإمكان و دائماً اشتقاد استثناءاتك من شيء ضمن التسلسل الهرمي. قد ترغب في قراءة استثناءات جزء من Farshall Cline's C ++ الأسئلة الشائعة - اقرأ الأسئلة الشائعة 17.6., 17.9, 17.10, ، و 17.12 خاصه.

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

class foo_exception {
public:
    explicit foo_exception(std::string msg_): m_msg(msg_) {}
    virtual ~foo_exception() {}
    virtual void raise() { throw *this; }
    virtual std::string const& msg() const { return m_msg; }
protected:
    foo_exception(foo_exception const& other): m_msg(other.m_msg) {}
private:
    std::string m_msg;
};

class bar_exception: public foo_exception {
public:
    explicit bar_exception(std::string msg_):
        foo_exception(msg_), m_error_number(errno) {}
    virtual void raise() { throw *this; }
    int error_number() const { return m_error_number; }
protected:
    bar_exception(bar_exception const& other):
        foo_exception(other), m_error_number(other.m_error_number) {}
private:
    int m_error_number;
};

هذه الفكرة هي جعل منشئ النسخ المحمي وإجبار المستخدمين على الاتصال Class(args).raise() بدلاً من throw Class(args). وبعد يتيح لك ذلك رمي استثناء مرتبط متعدد الأيام يمكن للمستخدمين أن يمسكوا فقط بالرجوع إليها. أي محاولة للقبض حسب القيمة ينبغي يتم الترحيب بها مع تحذير مترجم لطيف. شيء مثل:

foo.cpp: 59: خطأ: 'bar_exception :: bar_Exception (const bar_exception &) محمي

foo.cpp: 103: خطأ: في هذا السياق

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

Foo.CPP: في الوظيفة "الفراغ H ()":

foo.cpp: 31: خطأ: 'foo_Exception :: foo_Exception (const foo_exception &) محمي

foo.cpp: 93: خطأ: في هذا السياق

foo.cpp: 31: خطأ: 'foo_Exception :: foo_Exception (const foo_exception &) محمي

foo.cpp: 93: خطأ: في هذا السياق

بشكل عام، أود الاعتماد على معايير الترميز والوثائق التي تفيد بأن يجب عليك دائما التقاط بالرجوع إليها. تأكد من أن مكتبتك يمسك باستثناءات تقودها بالرجوع إليها ورمي أشياء جديدة (على سبيل المثال، throw Class(constructorArgs) أو throw;). أتوقع أن يكون لدى مبرمجي C ++ الآخرين نفس المعرفة - لكن إضافة ملاحظة إلى أي وثائق فقط للتأكد.

نصائح أخرى

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

الحل لمشكلتك هو دائما التقاط بالرجوع إلى ذلك بدلا من ذلك:

try {
    // some code...
    throw MyException("lp0 is on fire!");
} catch (MyException const &ex) {
    // handle exception
}

(const- غير اختياري، لكنني دائما أضعها لأن هناك حاجة لتعديل كائن الاستثناء.)

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

الطرق المحمولة التي عثرت عليها لمنع عملاء مكتبتي من استثناءات اللحاق بالركض بشكل غير صحيح حسب القيمة

  1. رمي الاستثناءات من الداخل رفع افتراضي طرق فصول الاستثناء، وإجراء نسخ منشئين محميين. (شكرا D.Shawley)
  2. قم بإلقاء استثناءات مشتقة من المكتبة ونشر فئات أساسية استثناء للعملاء للقبض عليها. يمكن أن تكون الفصول الأساسية من منشئات النسخ المحمية، والتي تسمح فقط بالطريقة الجيدة لجباتها. (المشار هنا لسؤال Simmilar)

يحتاج معيار C ++ الذي يحتاج إلى أن نسخ المنشئ يجب أن يكون متاحا عند نقطة الرمية. Visual C ++ 8.0 في تكويني انتهك هذا الجزء من المعيار من خلال عدم إنفاذ وجود منشئ النسخ. في القسم 15.1.3:

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

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

تم نشر هذه الإجابة عن طريق البريد في السؤال، أزلته من السؤال والنشر كإجابة منفصلة.

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top