मूल अपवाद के पुनर्विचार पर C ++ अपवाद प्रश्न


117

कैच में निम्नलिखित परिशिष्ट () को एपेंड () कहा जाता है के प्रभाव को देखने के लिए पुनर्विचार अपवाद का कारण होगा?

try {
  mayThrowMyErr();
} catch (myErr &err) {
  err.append("Add to my message here");
  throw; // Does the rethrow exception reflect the call to append()?
}

इसी तरह, अगर मैं इसे इस तरह से फिर से लिखता हूं, तो क्या बिट स्लाइसिंग होगी यदि वास्तविक अपवाद myErr द्वारा लिया गया है?

try {
  mayThrowObjectDerivedFromMyErr();
} catch (myErr &err) {
  err.append("Add to my message's base class here");
  throw err; // Do I lose the derived class exception and only get myErr?
}

जवाबों:


150

दोनों मामलों में, चूंकि आप संदर्भ से पकड़ते हैं, आप प्रभावी रूप से मूल अपवाद ऑब्जेक्ट की स्थिति को बदल रहे हैं (जिसे आप एक जादुई मेमोरी स्थान में रहने के रूप में सोच सकते हैं जो बाद में होने वाली अनिच्छा के दौरान मान्य रहेगा - 0x98e7058नीचे दिए गए उदाहरण में)। तथापि,

  1. पहले मामले में, जब से आप के साथ पुनर्विचार करते हैं throw;(जो, इसके विपरीत throw err;, अपने संशोधनों के साथ, मूल अपवाद ऑब्जेक्ट को संरक्षित करता है, तो "जादुई स्थान" पर 0x98e7058) ने कहा कि अपील में कॉल को प्रतिबिंबित करेगा ()
  2. दूसरे मामले में, के बाद से आप स्पष्ट रूप से कुछ फेंक, एक प्रतिलिपि की errजा बनाया तो एक अलग "जादुई स्थान" पर नए सिरे से फेंक दिया जाएगा ( 0x98e70b0- क्योंकि सभी के लिए संकलक जानता errढेर पर एक वस्तु, हो सकता है के बारे में unwinded होने के लिए eथा पर 0xbfbce430, "जादुई स्थान" पर नहीं 0x98e7058), इसलिए आप बेस क्लास उदाहरण की कॉपी-निर्माण के दौरान व्युत्पन्न वर्ग-विशिष्ट डेटा खो देंगे

यह बताने के लिए कि क्या हो रहा है: सरल कार्यक्रम

#include <stdio.h>

struct MyErr {
  MyErr() {
    printf("  Base default constructor, this=%p\n", this);
  }
  MyErr(const MyErr& other) {
    printf("  Base copy-constructor, this=%p from that=%p\n", this, &other);
  }
  virtual ~MyErr() {
    printf("  Base destructor, this=%p\n", this);
  }
};

struct MyErrDerived : public MyErr {
  MyErrDerived() {
    printf("  Derived default constructor, this=%p\n", this);
  }
  MyErrDerived(const MyErrDerived& other) {
    printf("  Derived copy-constructor, this=%p from that=%p\n", this, &other);
  }
  virtual ~MyErrDerived() {
    printf("  Derived destructor, this=%p\n", this);
  }
};

int main() {
  try {
    try {
      MyErrDerived e;
      throw e;
    } catch (MyErr& err) {
      printf("A Inner catch, &err=%p\n", &err);
      throw;
    }
  } catch (MyErr& err) {
    printf("A Outer catch, &err=%p\n", &err);
  }
  printf("---\n");
  try {
    try {
      MyErrDerived e;
      throw e;
    } catch (MyErr& err) {
      printf("B Inner catch, &err=%p\n", &err);
      throw err;
    }
  } catch (MyErr& err) {
    printf("B Outer catch, &err=%p\n", &err);
  }
  return 0;
}

परिणाम:

  Base default constructor, this=0xbfbce430
  Derived default constructor, this=0xbfbce430
  Base default constructor, this=0x98e7058
  Derived copy-constructor, this=0x98e7058 from that=0xbfbce430
  Derived destructor, this=0xbfbce430
  Base destructor, this=0xbfbce430
A Inner catch, &err=0x98e7058
A Outer catch, &err=0x98e7058
  Derived destructor, this=0x98e7058
  Base destructor, this=0x98e7058
---
  Base default constructor, this=0xbfbce430
  Derived default constructor, this=0xbfbce430
  Base default constructor, this=0x98e7058
  Derived copy-constructor, this=0x98e7058 from that=0xbfbce430
  Derived destructor, this=0xbfbce430
  Base destructor, this=0xbfbce430
B Inner catch, &err=0x98e7058
  Base copy-constructor, this=0x98e70b0 from that=0x98e7058
  Derived destructor, this=0x98e7058
  Base destructor, this=0x98e7058
B Outer catch, &err=0x98e70b0
  Base destructor, this=0x98e70b0

और देखें:


24

यह प्रश्न पुराना है और इसमें पूछे गए समय का उत्तर उपयुक्त है। हालांकि, मैं सिर्फ C ++ 11 के बाद से उचित अपवाद हैंडलिंग पर एक नोट जोड़ना चाहता हूं और मेरा मानना ​​है कि यह बहुत ही अच्छी तरह से मेल खाता है जो आप अपने एपेंड फ़ंक्शन के साथ प्राप्त करने की कोशिश कर रहे थे:

का उपयोग करें std::nested_exceptionऔरstd::throw_with_nested

यह StackOverflow पर यहाँ और यहाँ वर्णित है , कैसे आप एक डिबगर या बोझिल लॉगिंग की आवश्यकता के बिना अपने कोड के अंदर अपने अपवादों पर एक बैकट्रेस प्राप्त कर सकते हैं , बस एक उचित अपवाद हैंडलर लिखकर जो अपवादों को फिर से उखाड़ फेंकेंगे।

चूंकि आप इसे किसी भी व्युत्पन्न अपवाद वर्ग के साथ कर सकते हैं, इसलिए आप इस तरह के बैकट्रेस में बहुत सारी जानकारी जोड़ सकते हैं! आप GitHub पर मेरे MWE पर एक नज़र डाल सकते हैं , जहां एक बैकट्रेस कुछ इस तरह दिखेगी:

Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"

8

हां, रीथ्रोइंग मूल अपवाद ऑब्जेक्ट को रीथ्रो करता है, जिसे आपने एक संदर्भ द्वारा संशोधित किया है। आप एक बेस क्लास संदर्भ भी पकड़ सकते हैं, इसके द्वारा संशोधित कर सकते हैं और फिर भी मूल व्युत्पन्न अपवाद प्रकार को पुनर्व्यवस्थित करने में सक्षम हो सकते हैं throw;


1

पहले सवाल के लिए, हाँ।

लेकिन दूसरे के लिए, व्लाद जवाब देखें। आपको प्रतिलिपि ctor को संभालने के लिए अपने अपवाद ऑब्जेक्ट को सावधानीपूर्वक डिज़ाइन करने की आवश्यकता होगी। सम्मेलन द्वारा, बेस क्लास अपने बच्चे को नहीं पहचानता है, इसलिए आप व्युत्पन्न वर्ग द्वारा किए गए अतिरिक्त डेटा को खो देंगे।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.