ব্যতিক্রম ক্লাস ডিজাইনিং


9

আমি একটি ছোট লাইব্রেরি কোড করছি এবং ব্যতিক্রম হ্যান্ডলিং ডিজাইন করতে আমার কিছুটা সমস্যা হচ্ছে। আমার অবশ্যই বলতে হবে যে আমি সি ++ ভাষার এই বৈশিষ্ট্য দ্বারা বিভ্রান্ত হয়ে পড়েছি এবং ব্যতিক্রম ক্লাসগুলির সাথে সঠিকভাবে কাজ করার জন্য আমাকে কী করতে হবে তা বোঝার জন্য আমি বিষয়টিতে যতটা সম্ভব পড়ার চেষ্টা করেছি।

আমি ক্লাসের system_errorএসটিএল বাস্তবায়ন থেকে অনুপ্রেরণা গ্রহণ করে এক ধরণের পদ্ধতির ব্যবহার করার সিদ্ধান্ত নিয়েছি future_error

আমার একটি ত্রুটি কোডযুক্ত একটি সূত্র রয়েছে:

enum class my_errc : int
{
    error_x = 100,
    error_z = 101,
    error_y = 102
};

এবং একটি একক ব্যতিক্রম শ্রেণি (এক error_categoryধরণের কাঠামোর সাথে system_errorমডেল দ্বারা প্রয়োজনীয় সমস্ত কিছুর ব্যাক আপ ):

// error category implementation
class my_error_category_impl : public std::error_category
{
    const char* name () const noexcept override
    {
        return "my_lib";
    }

    std::string  message (int ec) const override
    {
        std::string msg;
        switch (my_errc(ec))
        {
        case my_errc::error_x:
            msg = "Failed 1.";
            break;
        case my_errc::error_z:
            msg = "Failed 2.";
            break;
        case my_errc::error_y:
            msg = "Failed 3.";
            break;
        default:
            msg = "unknown.";
        }

        return msg;
    }

    std::error_condition default_error_condition (int ec) const noexcept override
    {
        return std::error_condition(ec, *this);
    }
};

// unique instance of the error category
struct my_category
{
    static const std::error_category& instance () noexcept
    {
        static my_error_category_impl category;
        return category;
    }
};

// overload for error code creation
inline std::error_code make_error_code (my_errc ec) noexcept
{
    return std::error_code(static_cast<int>(ec), my_category::instance());
}

// overload for error condition creation
inline std::error_condition make_error_condition (my_errc ec) noexcept
{
    return std::error_condition(static_cast<int>(ec), my_category::instance());
}

/**
 * Exception type thrown by the lib.
 */
class my_error : public virtual std::runtime_error
{
public:
    explicit my_error (my_errc ec) noexcept :
        std::runtime_error("my_namespace ")
        , internal_code(make_error_code(ec))
    { }

    const char* what () const noexcept override
    {
        return internal_code.message().c_str();
    }

    std::error_code code () const noexcept
    {
        return internal_code;
    }

private:
    std::error_code internal_code;
};

// specialization for error code enumerations
// must be done in the std namespace

    namespace std
    {
    template <>
    struct is_error_code_enum<my_errc> : public true_type { };
    }

আমার কেবলমাত্র কয়েকটি সংখ্যক পরিস্থিতি রয়েছে যেখানে আমি ত্রুটি কোড গণনার দ্বারা চিত্রিত ব্যতিক্রমগুলি ছুঁড়ে ফেলি।

উপরেরগুলি আমার এক পর্যালোকের সাথে ভালভাবে বসেনি। তিনি এই মতামত নিয়েছিলেন যে, আমার বেস ক্লাসের সাথে ব্যতিক্রম শ্রেণির একটি শ্রেণিবিন্যাস তৈরি করা উচিত ছিল std::runtime_errorকারণ শর্তে এম্বলড থাকা ত্রুটি কোডটি জিনিসগুলিকে মিশ্রিত করে - ব্যতিক্রম এবং ত্রুটি কোডগুলি - এবং একটি বিন্দুটি মোকাবেলা করা আরও ক্লান্তিকর হবে হ্যান্ডলিং এর; ব্যতিক্রম শ্রেণিবিন্যাস ত্রুটি বার্তাকে সহজে কাস্টমাইজ করার অনুমতি দেয়।

আমার একটা বিতর্ক হল যে আমি এটা সহজ রাখা, যে আমার লাইব্রেরি ব্যতিক্রম একাধিক প্রকারের নিক্ষেপ করার প্রয়োজন ছিল না চেয়েছিলেন ছিল এবং স্বনির্ধারণ যেমন স্বয়ংক্রিয়ভাবে পরিচালিত হয় এই ক্ষেত্রে সহজ হয় যে - error_codeএকটি হয়েছে error_categoryএর সাথে জড়িত অনূদিত করে সঠিক ত্রুটি বার্তায় কোড।

আমার বলতে হবে যে আমি আমার পছন্দটি ভালভাবে রক্ষা করি নি, টেস্টামেন্ট যে আমার এখনও সি ++ ব্যতিক্রম সম্পর্কিত কিছু ভুল ধারণা রয়েছে to

আমার ডিজাইনটি বুদ্ধিমান হয়েছে কিনা তা জানতে চাই। আমি যেটি বেছে নিলাম তা গ্রহণ করতে ব্যর্থ হওয়ায় আমি যেটি বেছে নিয়েছি তার চেয়ে অন্য পদ্ধতির সুবিধা কী হবে? আমি উন্নতি করতে কি করতে পারি?


2
আমি আপনার পর্যালোচকের সাথে নীতিগতভাবে একমত হতে চাই (ত্রুটি কোডগুলি এবং ব্যতিক্রমগুলির মিশ্রণটি আসলে এটি কার্যকর নয়)। তবে আপনার কাছে যদি একটি বিশাল পাঠাগার না থাকে তবে একটি বৃহত্তর শ্রেণিবিন্যাস থাকাও কার্যকর নয়। একটি বেস ব্যতিক্রম যা একটি বার্তা স্ট্রিং রয়েছে, কেবলমাত্র ব্যতিক্রম ব্যতীত যদি সমস্যা সমাধানের জন্য ব্যতিক্রমটির স্বতন্ত্রতা ব্যবহার করতে পারে তবে আলাদা ব্যতিক্রম থাকতে পারে।
মার্টিন ইয়র্ক

উত্তর:


9

আমি মনে করি আপনার সহকর্মী সঠিক ছিলেন: ক্লায়েন্ট কোডের ব্যতিক্রম-পরিচালনা প্রয়োজনের ভিত্তিতে নয়, শ্রেণিবদ্ধের মধ্যে প্রয়োগ করা কতটা সহজ on তার উপর ভিত্তি করে আপনি আপনার ব্যতিক্রম মামলাগুলি ডিজাইন করছেন।

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

try {
    your_library.exception_thowing_function();
} catch(const my_error& err) {
    switch(err.code()) { // this could also be an if
    case my_errc::error_x:
        // handle error here
        break;
    default:
        throw; // we are not interested in other errors
    }
}

একাধিক ব্যতিক্রম প্রকারের (পুরো শ্রেণিবিন্যাসের একটি সাধারণ বেস), আপনি লিখতে পারেন:

try {
    your_library.exception_thowing_function();
} catch(const my_error_x& err) {
    // handle error here
}

ব্যতিক্রম ক্লাস যেখানে দেখতে এইরকম:

// base class for all exceptions in your library
class my_error: public std::runtime_error { ... };

// error x: corresponding to my_errc::error_x condition in your code
class my_error_x: public my_error { ... };

কোনও গ্রন্থাগার লেখার সময়, অভ্যন্তরীণ বাস্তবায়নের (প্রয়োজনীয়ভাবে) স্বাচ্ছন্দ্যে নয়, এর ব্যবহারের স্বাচ্ছন্দ্যের দিকে দৃষ্টি নিবদ্ধ করা উচিত।

লাইব্রেরিতে সঠিকভাবে এটি করার প্রচেষ্টা নিষিদ্ধ হলে আপনার কেবল ব্যবহারের স্বাচ্ছন্দ্যে (ক্লায়েন্ট কোডটি কেমন দেখাচ্ছে) আপোষ করা উচিত।


0

আমি আপনার পর্যালোচকদের সাথে এবং @ ইউটিপিস্টিমের সাথে একমত। আপনি system_errorযখন ক্রস-প্ল্যাটফর্মের জিনিসগুলি প্রয়োগ করেন তখন কিছু পদ্ধতির ত্রুটি বিশেষ হ্যান্ডলিংয়ের প্রয়োজন হলে আপনি ব্যবহার করতে পারেন approach তবে এই ক্ষেত্রেও এটি কোনও ভাল সমাধান নয়, তবে মন্দ সমাধানও কম।

আরেকটা জিনিস. যখন ব্যতিক্রম শ্রেণিবিন্যাস তৈরি করবেন, তখন এটি খুব গভীর করবেন না। কেবলমাত্র সেই ব্যতিক্রম ক্লাসগুলি তৈরি করুন, যা ক্লায়েন্টদের দ্বারা প্রক্রিয়া করা যায়। বেশিরভাগ ক্ষেত্রে আমি কেবল std::runtime_errorএবং std::logic_errorstd::runtime_errorযখন কিছু ভুল হয়ে যায় তখন আমি ফেলে দিই এবং আমি কিছুই করতে পারি না (কম্পিউটার থেকে ব্যবহারকারী বের করে নেওয়ার ডিভাইস, তিনি সেই অ্যাপ্লিকেশনটি এখনও চলতে ভুলে গিয়েছিলেন), এবং std::logic_errorযখন প্রোগ্রাম লজিকটি ভেঙে যায় (ব্যবহারকারী অস্তিত্বহীন ডাটাবেস থেকে রেকর্ড মুছতে চেষ্টা করে তবে অপারেশন মুছে ফেলার আগে তিনি এটি পরীক্ষা করতে পারে, যাতে সে যুক্তিযুক্ত ত্রুটি পায়)।

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

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