سؤال

أنا أبحث عن إجابة في MS VC++.

عند تصحيح كبير C++ التطبيق, التي للأسف واسعة جدا استخدام C++ استثناءات.أحيانا قبض استثناء في وقت لاحق قليلا مما كنت فعلا تريد.

على سبيل المثال في البرمجية الزائفة:

FunctionB()
{
    ...
    throw e;
    ...
}

FunctionA()
{
    ...
    FunctionB()
    ...
}

try
{
    Function A()
}
catch(e)
{
    (<--- breakpoint)
    ...
}

لا يمكن التقاط الاستثناء مع نقطة توقف عند التصحيح.ولكن أنا لا يمكن أن تعود إذا حدث استثناء في FunctionA() أو FunctionB(), أو وظيفة أخرى.(على افتراض واسعة استثناء استخدام ضخمة نسخة من المثال أعلاه).

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

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

هل هناك أفضل الحلول لهذه المشكلة في لغات أخرى ؟

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

المحلول

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

#define throwException(message) \
    {                           \
        std::ostringstream oss; \
        oss << __FILE __ << " " << __LINE__ << " "  \
           << __FUNC__ << " " << message; \
        throw std::exception(oss.str().c_str()); \
    }

والتي سوف تضيف اسم الملف رقم السطر و اسم الدالة على الاستثناء النص (إذا كان المترجم يوفر كل وحدات الماكرو).

ثم رمي الاستثناءات باستخدام

throwException("An unknown enum value has been passed!");

نصائح أخرى

أنت أشرت إلى نقطة في المدونة.منذ كنت في المصحح ، يمكنك تعيين نقطة توقف على منشئ استثناء فئة أو مجموعة المصحح Visual Studio لكسر على طرح كل الاستثناءات (التصحيح->انقر فوق استثناءات على استثناءات C++ ، حدد القيت غير مسك الخيارات)

هناك كتاب ممتاز كتبها جون روبنز الذي يتناول العديد من صعوبة تصحيح الأسئلة.ويسمى الكتاب التصحيح تطبيقات Microsoft .NET و Microsoft Windows.على الرغم من عنوان الكتاب يحتوي على مجموعة من المعلومات حول التصحيح الأصلي C++ التطبيقات.

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

وضع نقطة توقف في الاستثناء منشئ الكائن.ستحصل على نقطة قبل طرح استثناء.

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

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

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

هنا هو كيف نفعل ذلك في C++ باستخدام دول مجلس التعاون الخليجي المكتبات:

#include <execinfo.h> // Backtrace
#include <cxxabi.h> // Demangling

vector<Str> backtrace(size_t numskip) {
    vector<Str> result;
    std::vector<void*> bt(100);
    bt.resize(backtrace(&(*bt.begin()), bt.size()));
    char **btsyms = backtrace_symbols(&(*bt.begin()), bt.size());
    if (btsyms) {
        for (size_t i = numskip; i < bt.size(); i++) {
            Aiss in(btsyms[i]);
            int idx = 0; Astr nt, addr, mangled;
            in >> idx >> nt >> addr >> mangled;
            if (mangled == "start") break;
            int status = 0;
            char *demangled = abi::__cxa_demangle(mangled.c_str(), 0, 0, &status);

            Str frame = (status==0) ? Str(demangled, demangled+strlen(demangled)) : 
                                      Str(mangled.begin(), mangled.end());
            result.push_back(frame);

            free(demangled);
        }
        free(btsyms);
    }
    return result;
}

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

لا يوجد معيار طريقة للقيام بذلك.

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

في VC++ على Win32/Win64 ، قد الحصول على استخدامها-ما يكفي من النتائج وتسجيل قيمة من المترجم الجوهرية _ReturnAddress() وضمان أن الاستثناء منشئ الفئة هو __declspec(noinline).بالتزامن مع التصحيح رمز المكتبة, أعتقد أنك يمكن أن تحصل على الأرجح اسم الدالة (و رقم السطر ، إذا كان الخاص بك .pdb يحتوي عليه) الذي يتوافق مع عنوان المرسل باستخدام SymGetLineFromAddr64.

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

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

أعتقد MSDev يسمح لك تعيين نقاط لكسر عندما يتم طرح استثناء.

بدلا من ذلك ضعي نقطة فاصل على منشئ من وجوه استثناء.

إذا كنت التصحيح من IDE ، انتقل إلى التصحيح->الاستثناءات ، انقر فوق القيت على استثناءات C++.

لغات أخرى ؟ حسنا, في جافا استدعاء هـ.printStackTrace () ؛ انها لا تحصل على أبسط بكثير من ذلك.

في حالة أي شخص مهتم ، زميل أجاب على هذا السؤال لي عبر البريد الإلكتروني:

ارتيم كتب:

هناك علم MiniDumpWriteDump() التي يمكن أن تفعل أفضل تحطم مقالب التي سوف تتيح رؤية كاملة برنامج الدولة ، مع كل المتغيرات العالمية ، إلخ.أما بالنسبة للدعوة مداخن, أشك في أنها يمكن أن تكون أفضل لأن من التحسينات...إلا إذا كنت بدوره (ربما بعض) تحسينات قبالة.

أيضا, أعتقد تعطيل وظائف مضمنة كله برنامج التحسين سوف تساعد الكثير جدا.

في الواقع ، هناك العديد من تفريغ أنواع ربما يمكنك أن تختار واحدة صغيرة بما فيه الكفاية ولكن لا تزال تواجه مزيد من المعلومات http://msdn.microsoft.com/en-us/library/ms680519(مقابل.85).aspx

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

لاحظت بعض تلك تفريغ أنواع غير معتمدة في dbghelp.dll الإصدار 5.1 التي نستخدمها.ونحن يمكن التحديث إلى أحدث 6.9 الإصدار على الرغم من أنني فقط التحقق من الترخيص لـ MS أدوات التصحيح-أحدث dbghelp.dll لا يزال موافق على إعادة توزيع.

يمكنني استخدام بلدي استثناءات.يمكنك التعامل معها بسيط جدا - كما أنها تحتوي على النص.يمكنني استخدام الشكل:

throw Exception( "comms::serial::serial( )", "Something failed!" );

أيضا لدي الاستثناء الثاني الشكل:

throw Exception( "comms::serial::serial( )", ::GetLastError( ) );

والتي يتم بعد ذلك تحويلها من قيمة DWORD أن الرسالة الفعلية باستخدام FormatMessage.باستخدام فيها/ما هو الشكل الذي سوف تظهر لك ما حدث و ما وظيفة.

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