2013-03-19 9 views
7

मैंने हाल ही में एक कार्यक्रम में लिखा था, जब मैं अपने "व्यापार तर्क" कोड को तृतीय-पक्ष या प्रोजेक्ट एपीआई में अपवाद ट्रिगर करता था तो लॉग करना चाहता था। (स्पष्टीकरण के लिए, जब मैं किसी एपीआई का उपयोग अपवाद का कारण बनता हूं तो लॉग इन करना चाहता हूं। यह वास्तविक throw से ऊपर कई फ्रेम हो सकता है, और वास्तविक catch से नीचे कई फ्रेम हो सकते हैं (जहां अपवाद पेलोड का लॉगिंग हो सकता है।) Iकोई अपवाद ट्रिगर होने पर लॉग इन कैसे होना चाहिए?

void former_function() 
{ 
    /* some code here */ 
    try 
    { 
     /* some specific code that I know may throw, and want to log about */ 
    } 
    catch(...) 
    { 
     log("an exception occurred when doing something with some other data"); 
     throw; 
    } 
    /* some code here */ 
} 

संक्षेप में, एक अपवाद तब होता है,, एक कैच-ऑल खंड बनाने के त्रुटि लॉग इन करें, और फिर से फेंक: निम्नलिखित किया था। मेरे दिमाग में यह सुरक्षित है। मुझे सामान्य पकड़ में पता है-सभी को बुरा माना जाता है, क्योंकि किसी के पास कोई उपयोगी जानकारी प्राप्त करने के लिए अपवाद का संदर्भ नहीं है। हालांकि, मैं इसे फिर से फेंकने जा रहा हूं, इसलिए कुछ भी नहीं खो गया है।

अब, अपने आप पर यह ठीक था, लेकिन कुछ अन्य प्रोग्रामर ने इस कार्यक्रम को संशोधित किया, और उपरोक्त का उल्लंघन समाप्त कर दिया। विशेष रूप से, उन्होंने एक मामले में कोशिश-ब्लॉक में बड़ी मात्रा में कोड डाला, और दूसरे में 'फेंक' हटा दिया और 'वापसी' रखा।

अब मुझे लगता है कि मेरा समाधान भंगुर था; यह भविष्य-संशोधन-सबूत नहीं था।

मुझे एक बेहतर समाधान चाहिए जिसमें इन समस्याओं को न हो।

मेरे पास एक और संभावित समाधान है जिसमें उपर्युक्त मुद्दा नहीं है, लेकिन मुझे आश्चर्य है कि दूसरे इसके बारे में क्या सोचते हैं। यह आरए II, विशेष रूप से एक वस्तु "स्कोप से बाहर निकलें" अगर std::uncaught_exceptionनिर्माण पर सच नहीं है कि परोक्ष चलाता है का उपयोग करता है, फिर भी विनाश पर सत्य है:

#include <ciso646> // not, and 
#include <exception> // uncaught_exception 

class ExceptionTriggeredLog 
{ 
private: 
    std::string const m_log_message; 
    bool const m_was_uncaught_exception; 
public: 
    ExceptionTriggeredLog(std::string const& r_log_message) 
     : m_log_message(r_log_message), 
     m_was_uncaught_exception(std::uncaught_exception()) 
    { 
    } 
    ~ExceptionTriggeredLog() 
    { 
     if(not m_was_uncaught_exception 
      and std::uncaught_exception()) 
     { 
      try 
      { 
       log(m_log_message); 
      } 
      catch(...) 
      { 
       // no exceptions can leave an destructor. 
       // especially when std::uncaught_exception is true. 
      } 
     } 
    } 
}; 

void potential_function() 
{ 
    /* some code here */ 
    { 
     ExceptionTriggeredLog exception_triggered_log("an exception occurred when doing something with some other data"); 
     /* some specific code that I know may throw, and want to log about */ 
    } 
    /* some code here */ 
} 

मैं जानना चाहता हूँ:

  • तकनीकी रूप से, क्या यह मजबूती से काम करेगा? प्रारंभ में ऐसा लगता है, लेकिन मुझे पता है कि std::uncaught_exception का उपयोग करने के बारे में कुछ चेतावनी हैं।
  • क्या मैं चाहता हूं कि पूरा करने के लिए एक और तरीका है?

नोट: मैंने इस प्रश्न को अद्यतन किया है। विशेष रूप से, मैं कर दिया है:

  • try/catch है कि शुरू में याद आ रही थी, जोड़ा log समारोह-कॉल के आसपास।
  • निर्माण पर std::uncaught_exception राज्य ट्रैकिंग को जोड़ा गया। इस मामले के खिलाफ यह गार्ड जहां यह ऑब्जेक्ट किसी अन्य विनाशक के 'प्रयास' ब्लॉक के अंदर बनाया गया है जो अपवाद स्टैक-अनइंडिंग के हिस्से के रूप में ट्रिगर किया जाता है।
  • नाम ऑब्जेक्ट बनाने के लिए नया 'संभावित_फंक्शन' तय किया गया है, अस्थायी ऑब्जेक्ट पहले जैसा नहीं है।
+1

आपको शायद यह पता है, लेकिन आपको 'लॉग' को 'अस्वीकरण' या 'फेंक()' के रूप में घोषित करने की आवश्यकता होगी या इसे {try {'और'} पकड़ें (...) ' – utnapistim

+0

@utnapistim अनुस्मारक के लिए धन्यवाद; मेरे सरल उदाहरण में यह 'फेंक() '/' noexcept' है, लेकिन सामान्य रूप से यह नहीं होगा, और' try'/'catch' होना चाहिए। –

+2

आपके साथी को क्या रोकता है प्रोग्रामर ब्रेसिज़ के बाहर "बड़ी मात्रा में कोड" डालने से? या उन्हें हटा दें क्योंकि वे अनावश्यक प्रतीत होते हैं? मैं कोशिश करूंगा एक टिप्पणी जोड़ना * कृपया इस फेंक को वापसी के साथ प्रतिस्थापित न करें। यह काम नहीं करता है! *। –

उत्तर

1

मुझे आपकी विधि पर कोई टिप्पणी नहीं है, लेकिन यह दिलचस्प लगता है! मेरे पास एक और तरीका है जो आप जो चाहते हैं उसके लिए भी काम कर सकता है, और थोड़ा और सामान्य उद्देश्य हो सकता है। इसके लिए सी ++ 11 से लैम्बडा की आवश्यकता होती है, हालांकि आपके मामले में कोई समस्या हो सकती है या नहीं भी हो सकती है।

यह एक सरल समारोह टेम्पलेट है कि एक लैम्ब्डा स्वीकार करता है, यह और कैच, लॉग चलाता है और सभी अपवादों rethrows है:

:

जिस तरह से आप (सरल मामले में) के लिए इसका इस्तेमाल इस तरह है

try_and_log ("An exception was thrown here...", [&] { 
    this_is_the_code(); 
    you_want_executed(); 
    and_its_exceptions_logged(); 
}); 

जैसा कि मैंने पहले कहा था, मुझे नहीं पता कि यह आपके अपने समाधान के खिलाफ कैसे ढेर करता है। ध्यान दें कि लैम्ब्डा सब कुछ को अपने संलग्न दायरे से कैप्चर कर रहा है, जो काफी सुविधाजनक है। यह भी ध्यान रखें कि मैंने वास्तव में यह कोशिश नहीं की है, इसलिए संकलन त्रुटियों, तार्किक समस्याओं और/या परमाणु युद्धों का परिणाम हो सकता है।

समस्या जो मैं यहां देखता हूं वह यह है कि इसे मैक्रो में लपेटना आसान नहीं है, और आपके सहयोगियों को [=] { और } भागों को सही ढंग से लिखने की उम्मीद है और हर समय बहुत अधिक हो सकता है!

रैपिंग और बेवकूफ प्रूफिंग प्रयोजनों के लिए, आप शायद दो मैक्रो की आवश्यकता होगी: एक TRY_AND_LOG_BEGIN लैम्ब्डा के लिए खोलने ब्रेस तक पहली पंक्ति फेंकना और एक TRY_AND_LOG_END समापन ब्रेस और कोष्ठक फेंकना। इसलिए जैसा:

#define TRY_AND_LOG_BEGIN(message) try_and_log (message, [&] { 
#define TRY_AND_LOG_END()   }) 

और आप उन्हें इस तरह का उपयोग करें:

TRY_AND_LOG_BEGIN ("Exception happened!") // No semicolons here! 
    whatever_code_you_want(); 
TRY_AND_LOG_END(); 

कौन सा है - अपने दृष्टिकोण के आधार पर - या तो एक शुद्ध लाभ या शुद्ध हानि है! । (मैं व्यक्तिगत रूप से, सीधी समारोह कॉल और लैम्ब्डा वाक्य रचना पसंद करते हैं जो मुझे और अधिक नियंत्रण और पारदर्शिता देता

इसके अलावा, यह कोड ब्लॉक के अंत में लॉग संदेश लिखने के लिए संभव है, बस try_and_log के दो मापदंडों स्विच फ़ंक्शन

+0

मुझे यकीन है कि मैक्रोज़ * कच्चे * 'try_and_log' की तुलना में कोई भी मूल्य जोड़ता है; दोनों मामलों में एक और कोडर आसानी से नए बयान जोड़ सकता है। मेरे मूल 'पूर्व_फंक्शन' उदाहरण की तुलना में, यह अंतर्निहित 'try'/'catch (...) {लॉग (" खराब सामग्री "); फेंक;}' को छिपाता है ताकि पुनः फेंक दिया जा सके, और 'पकड़' (...) 'कोड, कोड में अन्य स्थानों में कॉपी-पेस्ट नहीं किया गया है जो सभी अपवादों को नहीं पकड़ना चाहिए। –

संबंधित मुद्दे