মূল ব্যতিক্রম পুনর্বিবেচনার ক্ষেত্রে সি ++ ব্যতিক্রম প্রশ্ন


117

ক্যাচের নিম্নলিখিত সংযোজন () পুনরায় উত্থাপিত ব্যতিক্রম ডাকা হবে অ্যাপেন্ড () এর প্রভাব দেখতে?

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

একইভাবে, আমি যদি এটিকে আবার লিখি, তবে সত্যিকারের ব্যতিক্রমটি MyEr দ্বারা উদ্ভূত হলে বিট স্লাইসিং ঘটবে?

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হবে এবং আবার নতুন করে ছুঁড়ে ফেলা হবে (একটি ভিন্ন " icalন্দ্রজালিক অবস্থানে" 0x98e70b0- কারণ সমস্ত সংকলক জানে errযে স্ট্যাকের কোনও জিনিস অপরিবর্তিত থাকতে পারে, যেমনটি 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

এই প্রশ্নটি বরং পুরানো এবং এটির জিজ্ঞাসা করা সময়ের উপযুক্ত উত্তর ছিল। তবে, আমি কেবল সি ++ 11 সাল থেকে কীভাবে সঠিক ব্যতিক্রম হ্যান্ডলিং করবেন সে সম্পর্কে একটি নোট যুক্ত করতে চাই এবং আমি বিশ্বাস করি এটি আপনার সংযোজন ফাংশনটির সাথে আপনি কী অর্জন করার চেষ্টা করছেন তার সাথে এটি খুব ভালভাবে মিলে যায়:

ব্যবহার করুন std::nested_exceptionএবংstd::throw_with_nested

এটি স্ট্যাকওভারফ্লোতে এখানে এবং এখানে বর্ণিত হয়েছে , আপনি কীভাবে কোনও ডিবাগার বা কষ্টকর লগিংয়ের প্রয়োজন ছাড়াই আপনার কোডের অভ্যন্তরে ব্যতিক্রমগুলি পেতে পারেন , কেবলমাত্র একটি উপযুক্ত ব্যতিক্রম হ্যান্ডলার লিখে যা নেস্টেড ব্যতিক্রমগুলি পুনর্বিবেচনা করবে।

যেহেতু আপনি যে কোনও উদ্ভূত ব্যতিক্রম শ্রেণীর সাহায্যে এটি করতে পারেন, আপনি এই জাতীয় ব্যাকট্রাসে প্রচুর তথ্য যুক্ত করতে পারেন! আপনি গিটহাবের আমার এমডব্লিউইতে একবার দেখে নিতে পারেন , যেখানে ব্যাকট্রিসটি এরকম কিছু দেখায়:

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

প্রথম প্রশ্নের জন্য, হ্যাঁ

তবে দ্বিতীয়টির জন্য, ভ্লাদ উত্তরটি দেখুন। আপনার অনুলিপি অবজেক্টটি অনুলিপি করে কপির সিটার পরিচালনা করতে হবে। কনভেনশন অনুসারে, বেস ক্লাসটি তার শিশুটিকে চিনতে পারে না তাই সম্ভবত আপনি উত্পন্ন শ্রেণীর দ্বারা চালিত অতিরিক্ত ডেটা হারাবেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.