কীভাবে একটি সি ++ ফেলবেন


259

আমার কাছে ব্যতিক্রম হ্যান্ডলিংয়ের খুব খারাপ ধারণা রয়েছে (যেমন, কীভাবে নিজের উদ্দেশ্যে উদ্দেশ্যে ছুঁড়ে ফেলতে, চেষ্টা করতে, স্টেটমেন্টগুলি ধরতে হয়)।

উদাহরণস্বরূপ, আমি নিম্নলিখিত হিসাবে একটি ফাংশন সংজ্ঞায়িত করেছি: int compare(int a, int b){...}

আমি বা ফাংশনটি নেতিবাচক হলে কিছু বার্তা নিয়ে একটি ব্যতিক্রম ছুঁড়ে ফেলাতে চাই।

ফাংশনের সংজ্ঞায় আমি কীভাবে এটির কাছে যেতে পারি?


3
আপনার এটি পড়তে হবে: getw.ca/publications/mill22.htm
অলিভার চার্লসওয়ার্থ

37
@ অলিচার্লসওয়ার্থ, আপনি কি মনে করেন না যে বেসিকগুলি সম্পর্কে বিভ্রান্ত এমন কাউকে ফেলে দেওয়া কিছুটা কম?
মার্ক রান্সম

6
অতিরিক্ত অতিরিক্ত ব্যতিক্রমগুলি এড়ানো উচিত। যদি আপনি না চান যে আপনার কলার নেতিবাচক মানগুলি পাস করবে তবে এটি unsigned intআপনার ফাংশনের স্বাক্ষরের পরামিতি হিসাবে নির্দিষ্ট করে আরও স্পষ্ট করে তুলবে । তারপরে আবার আমি সেই বিদ্যালয়ের মধ্যে আছি যা আপনাকে কেবল ব্যতিক্রমী জিনিসগুলির জন্য ব্যতিক্রম ছুঁড়ে ফেলা উচিত catch
এজেজি 85

1
@ মার্ক: কারও ক্ষেত্রে কারও throw()ব্যতিক্রমের স্পেসিফিকেশন ব্যবহার করা উচিত কিনা তা নিয়ে আমি মূলত প্রশ্নটিকে ভুল বুঝেছিলাম ।
অলিভার চার্লসওয়ার্থ

উত্তর:


363

সরল:

#include <stdexcept>

int compare( int a, int b ) {
    if ( a < 0 || b < 0 ) {
        throw std::invalid_argument( "received negative value" );
    }
}

স্ট্যান্ডার্ড লাইব্রেরিটি আপনি ফেলতে পারেন এমন অন্তর্নির্মিত ব্যতিক্রমী সামগ্রীর একটি দুর্দান্ত সংগ্রহ নিয়ে আসে । মনে রাখবেন যে আপনার সর্বদা মান দ্বারা নিক্ষেপ করা উচিত এবং রেফারেন্সের মাধ্যমে ধরা উচিত:

try {
    compare( -1, 3 );
}
catch( const std::invalid_argument& e ) {
    // do stuff with exception... 
}

প্রতিটি চেষ্টা করার পরে আপনার একাধিক ক্যাচ () স্টেটমেন্ট থাকতে পারে, তাই আপনি চাইলে আলাদা আলাদা ব্যতিক্রম প্রকারগুলি পরিচালনা করতে পারেন।

আপনি ব্যতিক্রমগুলিও আবার ফেলে দিতে পারেন:

catch( const std::invalid_argument& e ) {
    // do something

    // let someone higher up the call stack handle it if they want
    throw;
}

এবং নির্বিশেষে ব্যতিক্রমগুলি ধরতে:

catch( ... ) { };

26
এবং আপনার সর্বদা কনস্ট্যান্ড হিসাবে ব্যতিক্রমগুলি ধরা উচিত
অ্যাড্রিয়ান কর্নিশ

2
@ টেরিলিআইফেইং যদি কাস্টম ব্যতিক্রমগুলি আরও বেশি অর্থবোধ করে তবে এটির জন্য যান। আপনি এখনও স্ট্যান্ড :: ব্যতিক্রম থেকে প্রাপ্ত এবং ইন্টারফেসটি একই রাখতে চাইবেন।
nsanders

2
আবার +1 করেছে তবে আমি মনে করি এটির পক্ষে এটি অত্যন্ত গুরুত্বপূর্ণ - কারণ এটি এখন এটি একটি অস্থায়ী অবজেক্টের সত্যটি তুলে ধরে - সুতরাং পরিবর্তনটি অকেজো।
অ্যাড্রিয়ান কর্নিশ

2
@ অ্যাড্রিয়ান কর্নিশ: যদিও এটি আসলে অস্থায়ী নয়। নন-কনস্ট্যান্ট ক্যাচগুলি কার্যকর হতে পারে
GManNickG

26
আপনি সাধারণত ধরা throw;পড়েছিলেন (আসল বস্তুর পুনর্বিবেচনা এবং এর ধরণ সংরক্ষণ করে) এর পরিবর্তে throw e;(ধরা পড়া বস্তুর একটি অনুলিপি নিক্ষেপ করা, সম্ভবত এটির ধরন পরিবর্তন করা)।
মাইক সিমুর

17

throwযেখানে প্রয়োজন সেখানে কেবল যুক্ত করুন এবং tryতাত্ক্ষণিকভাবে কলকারীকে কল করুন। কনভেনশন অনুসারে আপনার কেবল এমন জিনিস ফেলে দেওয়া উচিত যা প্রথমে std::exceptionঅন্তর্ভুক্ত থাকে <stdexcept>

int compare(int a, int b) {
    if (a < 0 || b < 0) {
        throw std::invalid_argument("a or b negative");
    }
}

void foo() {
    try {
        compare(-1, 0);
    } catch (const std::invalid_argument& e) {
        // ...
    }
}

এছাড়াও, বুস্ট দেখুনধারণা


15

যদিও এই প্রশ্নটি বরং পুরানো এবং ইতিমধ্যে উত্তর দেওয়া হয়েছে, তবে আমি কেবল সি ++ 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 std::invalid_argument( "received negative value" );

অথবা আপনি এটি এর মতো সংজ্ঞা দিতে পারেন:

std::runtime_error greatScott("Great Scott!");          
double getEnergySync(int year) {                        
    if (year == 1955 || year == 1885) throw greatScott; 
    return 1.21e9;                                      
}                                                       

সাধারণত, আপনার try ... catchএটির মতো একটি ব্লক থাকবে :

try {
// do something that causes an exception
}catch (std::exception& e){ std::cerr << "exception: " << e.what() << std::endl; }

6

কাস্টম ব্যতিক্রমগুলির ক্ষেত্রে এখানে একটি অতিরিক্ত নোট বর্ণিত অন্যান্য উত্তরে ADD করতে চেয়েছিলেন ।

আপনি যখন নিজের কাস্টম ব্যতিক্রম তৈরি করেন সেই ক্ষেত্রে std::exception, যখন আপনি "সমস্ত সম্ভাব্য" ব্যতিক্রম প্রকারগুলি ধরেন, আপনার সর্বদা catchধরা পড়তে পারে এমন "সর্বাধিক প্রাপ্ত" ব্যতিক্রম প্রকারের সাথে ক্লজগুলি শুরু করা উচিত । (কি উদাহরণ দেখুন না করতে):

#include <iostream>
#include <string>

using namespace std;

class MyException : public exception
{
public:
    MyException(const string& msg) : m_msg(msg)
    {
        cout << "MyException::MyException - set m_msg to:" << m_msg << endl;
    }

   ~MyException()
   {
        cout << "MyException::~MyException" << endl;
   }

   virtual const char* what() const throw () 
   {
        cout << "MyException - what" << endl;
        return m_msg.c_str();
   }

   const string m_msg;
};

void throwDerivedException()
{
    cout << "throwDerivedException - thrown a derived exception" << endl;
    string execptionMessage("MyException thrown");
    throw (MyException(execptionMessage));
}

void illustrateDerivedExceptionCatch()
{
    cout << "illustrateDerivedExceptionsCatch - start" << endl;
    try 
    {
        throwDerivedException();
    }
    catch (const exception& e)
    {
        cout << "illustrateDerivedExceptionsCatch - caught an std::exception, e.what:" << e.what() << endl;
        // some additional code due to the fact that std::exception was thrown...
    }
    catch(const MyException& e)
    {
        cout << "illustrateDerivedExceptionsCatch - caught an MyException, e.what::" << e.what() << endl;
        // some additional code due to the fact that MyException was thrown...
    }

    cout << "illustrateDerivedExceptionsCatch - end" << endl;
}

int main(int argc, char** argv)
{
    cout << "main - start" << endl;
    illustrateDerivedExceptionCatch();
    cout << "main - end" << endl;
    return 0;
}

বিঃদ্রঃ:

0) যথাযথ ক্রমটি বিপরীত হওয়া উচিত, অর্থাত্ প্রথমে আপনাকে catch (const MyException& e)অনুসরণ করা হবে catch (const std::exception& e)

1) যেহেতু আপনি দেখতে পারেন, আপনি যখন প্রোগ্রাম চালানো হয়, প্রথম ধরা দফা মৃত্যুদন্ড কার্যকর করা হবে (যা সম্ভবত তুমি কি করেছিলে না প্রথম স্থানে চেয়েছিলেন)।

2) প্রথম ধরণের ধরণের ধরণের ধরণটি টাইপের হলেও std::exception, "যথাযথ" সংস্করণটি what()বলা হবে - কারণ এটি রেফারেন্সের মাধ্যমে ধরা পড়ে (কমপক্ষে ধরা পড়া যুক্তির std::exceptionধরণটি মান অনুসারে পরিবর্তন করুন - এবং আপনি অভিজ্ঞতাটি অনুভব করবেন) ক্রিয়াকলাপে "বস্তু কাটা" ঘটনা)।

3) "ব্যতিক্রমের কারণে XXX ব্যতিক্রম ছুঁড়ে ফেলার কারণে" কিছু কোড ... "ব্যতিক্রম প্রসঙ্গে শ্রদ্ধার সাথে গুরুত্বপূর্ণ জিনিসগুলি করে, আপনার কোডটির এখানে দুর্ব্যবহার রয়েছে।

৪) ধরা পড়া বস্তুগুলি যেমন "নরমাল" অবজেক্টের মতো হয়: class Base{};এবং class Derived : public Base {}...

5) g++ 7.3.0উবুন্টু 18.04.1 এ একটি সতর্কতা উত্পন্ন করে যা উল্লিখিত সমস্যাটিকে নির্দেশ করে:

ফাংশনে 'অকার্যকর ইলাস্ট্রেটডেরাইভেড এক্সেকশন ক্যাচ ()': আইটেম 12 লিনাক্স সিপিপি: 48: 2: সতর্কতা: 'মাই এক্সেক্সপশন' টাইপ ব্যতীত ধরা পড়বে (কন মাই এক্সেক্সপশন এবং ই) ^ ~~~~

আইটেম 12 লিনাকস সিপিপি: 43: 2: সতর্কতা: 'স্টাড :: ব্যতিক্রম' ক্যাচ (কনস্ট্যান্ড ব্যতিক্রম এবং ই) এর আগের হ্যান্ডলার দ্বারা ^ warning

আবার , আমি এই উত্তর শুধুমাত্র হয় বলবে, এডিডি অন্যান্য উত্তর এখানে বর্ণিত (আমি এই বিন্দু মূল্য উল্লেখ করা হয়, এখনো একটি মন্তব্য মধ্যেই বর্ণা না পারে)।

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