Orijinal istisnanın yeniden atılmasıyla ilgili C ++ İstisna soruları


117

Catch'teki aşağıdaki append (), rethrown istisnasının çağrılan append () etkisini görmesine neden olur mu?

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

Benzer şekilde, bu şekilde yeniden yazarsam, gerçek istisna myErr tarafından türetilirse bit dilimleme gerçekleşir mi?

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?
}

Yanıtlar:


150

Eğer referans olarak yakalamak beri Her iki durumda da, etkili (siz ikamet olarak düşünebiliriz orijinal istisna nesnesinin durumunu değiştiriyoruz müteakip çözülmesi sırasında geçerli kalacak büyülü hafıza konumu - 0x98e7058örneğin aşağıda). Ancak,

  1. İlk durumda, yeniden attığınız için throw;(bunun tersine throw err;, orijinal istisna nesnesini yaptığınız değişikliklerle, söz konusu "büyülü konumda" adresinde koruyan 0x98e7058) , append () çağrısını yansıtacaktır.
  2. Açıkça bir şey atmak beri ikinci durumda, bir kopyası ait errardından farklı "büyülü bir konumda" nde (yeniden atılmış oluşturulan edilecek 0x98e70b0- herkes için derleyici bildiği için errolarak açılmalıdır üzere gibi, yığın bir nesneyi olabilir eoldu adresindeki 0xbfbce430"sihirli konumda" değil 0x98e7058), bu nedenle temel sınıf örneğinin kopyalanması sırasında türetilmiş sınıfa özgü verileri kaybedersiniz .

Neler olduğunu göstermek için basit bir program:

#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;
}

Sonuç:

  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

Ayrıca bkz:


24

Bu soru oldukça eskidir ve sorulduğu zamana uygun bir cevabı vardır. Bununla birlikte, C ++ 11'den beri düzgün istisna işlemenin nasıl yapılacağına dair bir not eklemek istiyorum ve bunun, ekleme işlevinizle başarmaya çalıştığınız şeye çok iyi karşılık geldiğine inanıyorum:

Kullanım std::nested_exceptionvestd::throw_with_nested

StackOverflow'da burada ve burada , bir hata ayıklayıcıya veya zahmetli bir günlüğe gerek duymadan kodunuzdaki istisnalarınız hakkında bir geri izlemeyi, iç içe geçmiş istisnaları yeniden atacak uygun bir istisna işleyicisi yazarak nasıl elde edebileceğiniz açıklanmaktadır.

Bunu herhangi bir türetilmiş istisna sınıfı ile yapabileceğiniz için, böyle bir geri izlemeye birçok bilgi ekleyebilirsiniz! Ayrıca bir geri izleme şunun gibi görüneceği GitHub'daki MWE'me de bakabilirsiniz:

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

Evet, yeniden atma, bir referansla değiştirdiğiniz orijinal istisna nesnesini yeniden atar. Ayrıca bir temel sınıf referansını yakalayabilir, ona göre değiştirebilir ve yine de orijinal türetilmiş istisna türünü yeniden atabilirsiniz throw;.


1

ilk soru için evet.

ancak ikinci olarak Vlad cevabına bakın. copy ctor'u işlemek için istisna nesnenizi dikkatlice tasarlamanız gerekecektir. geleneksel olarak, temel sınıf alt sınıfını tanımaz, bu nedenle büyük olasılıkla türetilmiş sınıf tarafından taşınan ek verileri kaybedersiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.