সি ++ আরও ব্যতিক্রম ব্যতিক্রমগুলি বেশি পছন্দ করে seems
আমি কিছু দিক থেকে অবজেক্টিভ-সি এর চেয়ে কম প্রস্তাব করব কারণ সি ++ স্ট্যান্ডার্ড লাইব্রেরি সাধারণত প্রোগ্রামার ত্রুটিগুলিকে সাধারণত সবচেয়ে সাধারণ কেস ডিজাইন ফর্মের মধ্যে এলোমেলো-অ্যাক্সেস সিকোয়েন্সের আউট-অফ-সীমা অ্যাক্সেসের মতো ফেলে দেয় না operator[]
বা ( যেমন,) বা একটি অবৈধ পুনরাবৃত্তিকে ডিফেরেন্স করার চেষ্টা করছে। ভাষা সীমানার বাইরে কোনও অ্যারে অ্যাক্সেস করতে বা কোনও নাল পয়েন্টার বা এই ধরণের কিছুকে ডিফারেন্স করে on
ব্যতিক্রম হ্যান্ডলিং সমীকরণের বাইরে প্রোগ্রামার ত্রুটিগুলি গ্রহণ করা আসলে একটি বৃহত শ্রেণীর ত্রুটিগুলি দূরে নিয়ে যায় যা অন্যান্য ভাষা প্রায়শই সাড়া দেয় throwing
। সি ++ প্রবণতা রয়েছে assert
(যা রিলিজ / প্রোডাকশন বিল্ডগুলি সংকলন করে না, কেবলমাত্র ডিবাগ তৈরি করে) বা কেবল এইরকম ক্ষেত্রে ভুল (আউট ক্র্যাশ) হতে পারে, সম্ভবত অংশটি কারণ ভাষা এইরকম রানটাইম চেকগুলির ব্যয় আরোপ করতে চায় না যেমন প্রোগ্রামার ভুলগুলি সনাক্ত করার প্রয়োজন হবে যদি না প্রোগ্রামার নির্দিষ্টভাবে কোডটি লিখে নিজেই এই চেকগুলি সম্পাদন করে সেই ব্যয়গুলি পরিশোধ করতে না চায়।
সিটার এমনকি কোডিং স্ট্যান্ডার্ডগুলিতে এই জাতীয় ক্ষেত্রে ব্যতিক্রম এড়ানো এমনকি উত্সাহিত করে:
প্রোগ্রামিং ত্রুটির প্রতিবেদন করার ব্যতিক্রমটি ব্যবহার করার প্রাথমিক অসুবিধাটি হ'ল লাইনের অবস্থা অক্ষুণ্ন রেখে যেখানে লঙ্ঘনটি সনাক্ত করা হয়েছিল ঠিক সেই লাইনটিতে ডিবাগারটি চালু করতে চাইলে আপনি সত্যই অনাকাঙ্ক্ষিত স্ট্যাকটি ঘটতে চান না। সংক্ষেপে: এমন কিছু ত্রুটি রয়েছে যা আপনি জানেন যে ঘটতে পারে (আইটেমগুলি 69 থেকে 75 দেখুন)। অন্য সব কিছুর জন্য যা করা উচিত নয় এবং এটি প্রোগ্রামারের ত্রুটি যদি এটি করে তবে তা রয়েছে assert
।
এই নিয়মটি অগত্যা পাথর দ্বারা সেট করা হয় না। আরও কিছু মিশন-সমালোচনামূলক ক্ষেত্রে, এটি বলার অপেক্ষা রাখে না, মোড়ক এবং একটি কোডিং স্ট্যান্ডার্ড যা প্রোগ্রামার ত্রুটিগুলি ঘটে সেখানে একইভাবে লগ করে এবং throw
প্রোগ্রামার ভুলগুলির উপস্থিতিতে যেমন কোনও কিছুকে অবৈধ বলে বিবেচনা করার চেষ্টা করে বা এটি সীমা ছাড়িয়ে যায়, কারণ যদি সফ্টওয়্যারটির সুযোগ থাকে তবে এই ক্ষেত্রেগুলি পুনরুদ্ধার করতে ব্যর্থ হওয়া খুব ব্যয়বহুল হতে পারে। তবে সামগ্রিকভাবে ভাষাটির আরও সাধারণ ব্যবহার প্রোগ্রামার ভুলগুলির মুখে ফেলে না দেওয়ার পক্ষে থাকে।
বাহ্যিক ব্যতিক্রম
যেখানে আমি দেখতে পাই ব্যতিক্রমগুলি প্রায়শই সি ++ তে উত্সাহিত করা হয় (স্ট্যান্ডার্ড কমিটি অনুযায়ী, যেমন) প্রোগ্রামটির বাইরের কোনও বাহ্যিক উত্সের অপ্রত্যাশিত ফলাফল হিসাবে। একটি উদাহরণ মেমরি বরাদ্দ করতে ব্যর্থ হয়। অন্যটি সফ্টওয়্যারটি চালানোর জন্য প্রয়োজনীয় সমালোচনা ফাইলটি খুলতে ব্যর্থ হচ্ছে। অন্য একটি প্রয়োজনীয় সার্ভারের সাথে সংযোগ করতে ব্যর্থ হচ্ছে। আরেকটি হ'ল একজন ব্যবহারকারী এমন একটি অপারেশন বাতিল করতে একটি গর্ভপাত বোতাম জ্যাম করে যার সাধারণ কেস এক্সিকিউশন পাথটি এই বাহ্যিক বাধা অনুপস্থিত সফল হওয়ার প্রত্যাশা করে। এই সমস্ত জিনিস তাত্ক্ষণিক সফ্টওয়্যার এবং প্রোগ্রামারগণ যারা এটি লিখেছিল তাদের নিয়ন্ত্রণের বাইরে। তারা বাহ্যিক উত্স থেকে অপ্রত্যাশিত ফলাফল যা অপারেশন (যা সত্যই আমার বইতে একটি অবিচ্ছেদ্য লেনদেন হিসাবে ভাবা উচিত) সফল হতে সক্ষম হওয়া থেকে বিরত।
লেনদেন
আমি প্রায়শই try
একটি "লেনদেন" হিসাবে একটি ব্লককে দেখার জন্য উত্সাহিত করি কারণ লেনদেন সামগ্রিকভাবে সফল হওয়া উচিত বা সামগ্রিকভাবে ব্যর্থ হওয়া উচিত। যদি আমরা কিছু করার চেষ্টা করে থাকি এবং এটি অর্ধেকের মধ্যে ব্যর্থ হয়ে যায়, তবে প্রোগ্রাম স্টেটে যে কোনও পার্শ্ব প্রতিক্রিয়া / মিউটেশনগুলি সাধারণত সিস্টেমটিকে বৈধ অবস্থায় ফিরিয়ে আনার জন্য আবার ঘুরিয়ে নেওয়া দরকার যদিও লেনদেন কখনই কার্যকর হয় নি, একটি আরডিবিএমএস যেমন অর্ধেকের মধ্য দিয়ে কোনও ক্যোয়ারী প্রক্রিয়া করতে ব্যর্থ হয় তেমন ডাটাবেসের অখণ্ডতার সাথে আপোষ করা উচিত নয়। আপনি যদি কথিত লেনদেনে প্রোগ্রামের স্থিতিটি সরাসরি পরিবর্তন করেন তবে অবশ্যই কোনও ত্রুটির মুখোমুখি হওয়ার সময় এটি অবশ্যই "আনম্যাটেট" করতে হবে (এবং এখানে স্কাইপ গার্ডরা আরআইআইয়ের সাথে কার্যকর হতে পারে)।
সবচেয়ে সহজ বিকল্পটি আসল প্রোগ্রামের স্থিতিকে পরিবর্তন করতে পারে না ; আপনি এটির একটি অনুলিপি পরিবর্তন করতে পারেন এবং তারপরে, এটি সফল হলে, অনুলিপিটি মূলটির সাথে অদলবদল করুন (স্যুপটি নিক্ষেপ করতে পারে না তা নিশ্চিত করে)। যদি এটি ব্যর্থ হয়, অনুলিপিটি বাতিল করুন। আপনি সাধারণভাবে ত্রুটি পরিচালনা করার ক্ষেত্রে ব্যতিক্রম না ব্যবহার করলেও এটি প্রযোজ্য। একটি "ট্রানজেকশনাল" মানসিকতা যথাযথ পুনরুদ্ধারের মূল চাবিকাঠি, যদি কোনও ত্রুটির সম্মুখীন হওয়ার আগে প্রোগ্রামের রাষ্ট্রীয় পরিবর্তনগুলি ঘটে থাকে। এটি হয় পুরো হিসাবে সফল হয় বা পুরো ব্যর্থ হয়। এটি তার মিউটেশনগুলি অর্ধেকভাবে সফল করতে পারে না।
প্রোগ্রামাররা ত্রুটি বা ব্যতিক্রম হ্যান্ডলিং সঠিকভাবে কীভাবে করা যায় সে সম্পর্কে জিজ্ঞাসা করতে দেখলে এটি বিস্মিতভাবে প্রায়শই আলোচিত বিষয়গুলির মধ্যে একটি, তবুও অনেকের মধ্যে প্রোগ্রামের স্থিতিকে সরাসরি রূপান্তর করতে চায় এমন কোনও সফ্টওয়্যারটিতে ডান পাওয়া তাদের পক্ষে সবচেয়ে কঠিন is এর কার্যক্রম। বিশুদ্ধতা এবং অপরিবর্তনীয়তা থ্রেড-সুরক্ষার জন্য তারা যতটা সহায়তা করে ব্যতিক্রম-সুরক্ষা অর্জনে এখানে সহায়তা করতে পারে, রূপান্তর বা বাহ্যিক পার্শ্ব প্রতিক্রিয়া যা ঘটে না তা আবার ঘুরিয়ে দেওয়ার দরকার নেই।
কর্মক্ষমতা
ব্যতিক্রমগুলি ব্যবহার না করা বা না করা সম্পর্কে আরও একটি গাইডিক ফ্যাক্টর হ'ল পারফরম্যান্স, এবং আমি কিছু অবসেসিভ, পেনি-পিঞ্চিং, কাউন্টার-প্রোডাকটিভ পদ্ধতিতে বোঝাতে চাইছি না। অনেকগুলি সি ++ সংকলক প্রয়োগ করেন যা "জিরো-ব্যয় ব্যতিক্রম হ্যান্ডলিং" নামে পরিচিত।
এটি ত্রুটি-মুক্ত কার্যকরকরণের জন্য শূন্য রানটাইম ওভারহেড সরবরাহ করে, যা সি-রিটার্ন-ভ্যালু ত্রুটি পরিচালনা থেকেও ছাড়িয়ে যায় ses বাণিজ্য বন্ধ হিসাবে, একটি ব্যতিক্রমের প্রচারের একটি বিশাল ওভারহেড থাকে।
আমি এটি সম্পর্কে যা পড়েছি তা অনুসারে, এটি আপনার সাধারণ কেস এক্সিকিউশন পাথগুলিকে ব্যতিক্রমী পাথের জন্য ব্যয়কে ভারীভাবে স্কাই করার বিনিময়ে (সাধারণভাবে সি-স্টাইল ত্রুটি কোড পরিচালনা ও প্রচারের সাথে ওভারহেডেরও নয়) প্রয়োজন হয় না ( যার অর্থ throwing
এখন আগের চেয়ে বেশি ব্যয়বহুল)।
"ব্যয়বহুল" পরিমাণ নির্ধারণ করা কিছুটা কঠিন তবে শুরুর জন্য আপনি সম্ভবত কিছুটা শক্ত লুপে মিলিয়ন বার নিক্ষেপ করতে চান না। এই জাতীয় নকশা ধরে নিয়েছে যে ব্যতিক্রমগুলি সর্বদা বাম এবং ডান ঘটায় না।
অ ত্রুটি
এবং সেই পারফরম্যান্স পয়েন্টটি আমাকে অ-ত্রুটিগুলির দিকে নিয়ে আসে, যা আমরা অন্যান্য ভাষাগুলির সকল প্রকারের দিকে নজর দিলে আশ্চর্যরকমভাবে ম্লান হয়। তবে আমি বলব, উপরে উল্লিখিত শূন্যমূল্যের ইএইচ ডিজাইনটি দেওয়া, throw
আপনি কোনও সেটটিতে কোনও কী খুঁজে পাওয়া যাচ্ছেনা এর প্রতিক্রিয়ায় আপনি প্রায় নিশ্চিত করতে চান না। কারণ কেবল এটিই নয় যে তর্কাতীতভাবে একটি অ-ত্রুটি নয় (কীটি অনুসন্ধান করা ব্যক্তি সম্ভবত সেটটি তৈরি করে থাকতে পারে এবং এমন কীগুলির সন্ধান করতে পারে যা সর্বদা উপস্থিত থাকে না), তবে এটি সেই প্রসঙ্গে অত্যন্ত ব্যয়বহুল হবে।
উদাহরণস্বরূপ, একটি সেট ছেদকারী ক্রিয়াকলাপটি দুটি সেটের মধ্য দিয়ে লুপ করতে এবং সেগুলির সাদৃশ্যযুক্ত কীগুলি সন্ধান করতে পারে। যদি কোনও কী খুঁজে পেতে ব্যর্থ হয় তবে threw
আপনি অর্ধেক বা আরও বেশি পুনরুক্তিতে ব্যতিক্রমের মুখোমুখি হবেন:
Set<int> set_intersection(const Set<int>& a, const Set<int>& b)
{
Set<int> intersection;
for (int key: a)
{
try
{
b.find(key);
intersection.insert(other_key);
}
catch (const KeyNotFoundException&)
{
// Do nothing.
}
}
return intersection;
}
উপরোক্ত উদাহরণটি একেবারেই হাস্যকর এবং অতিরঞ্জিত, কিন্তু আমি দেখেছি, প্রোডাকশন কোডে কিছু লোক সি ++ তে কিছু ব্যতিক্রম ব্যবহার করে অন্য ভাষা থেকে এসেছিল এবং আমি মনে করি এটি একটি যুক্তিসঙ্গত বাস্তব বক্তব্য যে এটি ব্যতিক্রমগুলির উপযুক্ত ব্যবহার নয় think সি ++ এ। উপরের আরেকটি ইঙ্গিতটি হ'ল আপনি দেখতে পাচ্ছেন যে catch
ব্লকটিতে একেবারে করার মতো কিছুই নেই এবং কেবলমাত্র এই জাতীয় কোনও ব্যতিক্রমকে জোর করে উপেক্ষা করার জন্য লেখা হয়েছিল এবং এটি সাধারণত একটি ইঙ্গিত (যদিও কোনও গ্যারান্টর নয়) যে ব্যতিক্রমগুলি সম্ভবত সি ++ তে খুব উপযুক্তভাবে ব্যবহৃত হচ্ছে না।
এই ধরণের ক্ষেত্রে, ব্যর্থতার ইঙ্গিত দেয় এমন এক ধরণের রিটার্ন ভ্যালু (কোনও false
অবৈধ পুনরাবৃত্তির কাছে প্রত্যাবর্তন nullptr
বা যা কিছু প্রসঙ্গে বোঝায়) সাধারণত অনেক বেশি উপযুক্ত এবং অ-ত্রুটিযুক্ত প্রকারের কারণে প্রায়শই আরও ব্যবহারিক এবং উত্পাদনশীল কেস সাধারণত অ্যানালজিকাল catch
সাইটে পৌঁছানোর জন্য কিছু স্ট্যাক আনওয়ানডিং প্রক্রিয়া কল করে না ।
প্রশ্নাবলি
আমি যদি ব্যতিক্রমগুলি এড়াতে পছন্দ করি তবে আমাকে অভ্যন্তরীণ ত্রুটিযুক্ত পতাকাগুলি সহ যেতে হবে। এটি পরিচালনা করা কি খুব বেশি বিরক্ত হবে, বা এটি ব্যতিক্রমগুলির চেয়ে আরও ভাল কাজ করবে? উভয় ক্ষেত্রে একটি তুলনা সেরা উত্তর হবে।
সি ++ এ সম্পূর্ণভাবে ব্যতিক্রমগুলি এড়ানো আমার পক্ষে অত্যন্ত বিপরীত বলে মনে হয়, যদি না আপনি কিছু এম্বেড থাকা সিস্টেমে বা কোনও বিশেষ ধরণের ক্ষেত্রে কাজ করেন যা তাদের ব্যবহারকে নিষেধ করে (এমন ক্ষেত্রে আপনাকে সমস্ত এড়ানোর জন্য আপনার পথ থেকেও বেরিয়ে যেতে হবে) লাইব্রেরি এবং ভাষার কার্যকারিতা যা অন্যথায় throw
, কঠোরভাবে ব্যবহারের মতো nothrow
new
)।
যদি আপনাকে একেবারে কোনও কারণে ব্যতিক্রম এড়াতে হয় (উদাহরণস্বরূপ: আপনি যে মডিউলের সিআইপি রফতানি করেন তার সিআইপি সীমানা পেরিয়ে কাজ করছেন), অনেকেই আমার সাথে একমত হতে পারে না তবে আমি আসলে ওপেনএল-এর মতো একটি গ্লোবাল ত্রুটি হ্যান্ডলার / স্ট্যাটাস ব্যবহার করার পরামর্শ দিই glGetError()
। প্রতিটি থ্রেডে অনন্য ত্রুটির স্থিতি পেতে আপনি এটিকে থ্রেড-লোকাল স্টোরেজ ব্যবহার করতে পারেন।
এর জন্য আমার যুক্তিটি হ'ল আমি উত্পাদন পরিবেশে দলগুলিকে সমস্ত সম্ভাব্য ত্রুটির জন্য পুঙ্খানুপুঙ্খভাবে চেক করতে অভ্যস্ত নই, দুর্ভাগ্যবশত, যখন ত্রুটি কোডগুলি ফিরে আসে। যদি সেগুলি পুরোপুরি হয় তবে কিছু সি সি এপিআই প্রতিটি সি সি এপি কল সম্পর্কে ত্রুটির মুখোমুখি হতে পারে এবং পুরোপুরি চেক করার জন্য এমন কিছুর প্রয়োজন হবে:
if ((err = ApiCall(...)) != success)
{
// Handle error
}
... কোডের প্রায় প্রতিটি এক লাইনের সাথে এপিআই-কে অনুরোধ করা হয় যেমন এই ধরনের চেক প্রয়োজন। তবুও আমি পুরো দলগুলির সাথে কাজ করার ভাগ্য পাইনি। তারা প্রায়শই এই জাতীয় ত্রুটিগুলিকে প্রায় অর্ধেক উপেক্ষা করে sometimes ব্যতিক্রম সম্পর্কে এটি আমার কাছে সবচেয়ে বড় আবেদন। যদি আমরা এই এপিআইটি আবদ্ধ করি এবং throw
কোনও ত্রুটির মুখোমুখি হওয়ার ক্ষেত্রে এটি অভিন্ন করে তুলি তবে ব্যতিক্রম সম্ভবত উপেক্ষা করা যায় না এবং আমার দৃষ্টিতে এবং অভিজ্ঞতার দিক থেকে, ব্যতিক্রমগুলির শ্রেষ্ঠত্ব এইখানেই রয়েছে।
তবে যদি ব্যতিক্রমগুলি ব্যবহার না করা যায় তবে গ্লোবাল, প্রতি-থ্রেড ত্রুটির স্থিতির কমপক্ষে সুবিধা রয়েছে (আমার কাছে ত্রুটি কোডগুলি ফেরত দেওয়ার তুলনায় একটি বিশাল একটি) এটির চেয়ে কিছুটা পরে পূর্বের ত্রুটি ধরার সুযোগ থাকতে পারে একেবারে এটি মিস করার পরিবর্তে কিছু occurredিপি কোডবেসে ঘটেছে এবং কী ঘটেছিল তা সম্পর্কে আমাদের পুরোপুরি অজ্ঞান করে। ত্রুটিটি কয়েক লাইন আগে বা পূর্ববর্তী ফাংশন কলের মধ্যে ঘটেছে, তবে এই সফ্টওয়্যারটি এখনও ক্র্যাশ না হয়ে থাকতে পারে, আমরা আমাদের দিকে পিছন দিকে কাজ শুরু করতে এবং এটি কোথায় এবং কেন ঘটেছে তা নির্ধারণ করতে সক্ষম হতে পারি।
আমার কাছে মনে হচ্ছে যেহেতু পয়েন্টারগুলি বিরল, তাই আমি যদি ব্যতিক্রমগুলি এড়াতে পছন্দ করি তবে অভ্যন্তরীণ ত্রুটিযুক্ত পতাকাগুলি নিয়ে আমার যেতে হবে।
আমি অগত্যা বলব না যে পয়েন্টারগুলি বিরল। পাত্রে অন্তর্নিহিত ডেটা পয়েন্টার এবং একটি নতুন nullptr
কীওয়ার্ড পেতে এখনই সি ++ 11 এবং এর পরের পদ্ধতিগুলি রয়েছে । সাধারণত মেমরির মালিকানা / পরিচালনা করতে কাঁচা পয়েন্টার ব্যবহার করা বোকামি হিসাবে বিবেচনা করা হয় যদি আপনি unique_ptr
তার পরিবর্তে এর মতো কিছু ব্যবহার করতে পারেন তবে ব্যতিক্রমের উপস্থিতিতে এটি RAII- অনুসারী হওয়া কতটা সমালোচনামূলক। তবে মেমরির মালিকানা / পরিচালনা না করে এমন কাঁচা পয়েন্টারগুলিকে অগত্যা এত খারাপ বলে বিবেচনা করা হয় না (এমনকি সুটার এবং স্ট্রাস্ট্রাপের মতো লোকেরাও) এবং কখনও কখনও জিনিসগুলিকে নির্দেশ করার উপায় হিসাবে (জিনিসগুলিতে নির্দেশিত সূচকগুলি সহ) খুব ব্যবহারিক হিসাবে বিবেচিত হয় না।
তারা যুক্তিযুক্তভাবে স্ট্যান্ডার্ড কনটেইনার পুনরাবৃত্তির চেয়ে কম নিরাপদ নয় (কমপক্ষে মুক্তি, অনুপস্থিত চেক পুনরাবৃত্তকারী) যা তারা অবৈধ হওয়ার পরে যদি আপনি সেগুলি ডিলেফার করার চেষ্টা করেন তবে সনাক্ত করতে পারবেন না। সি ++ এখনও লজ্জাজনকভাবে কিছুটা বিপজ্জনক ভাষা, আমি বলব, যদি না এটির নির্দিষ্ট ব্যবহার না করে সবকিছু মুড়ে ফেলতে এবং এমনকি মালিকানাধীন কাঁচা পয়েন্টারগুলি গোপন না করে। এটি ব্যতিক্রমগুলির সাথে প্রায় সমালোচনামূলক যে সংস্থানগুলি RAII (যা সাধারণত কোনও রানটাইম ব্যয় করে আসে না) মেনে চলে, তবে এটির ব্যতীত কোনও বিকাশকারী স্পষ্টভাবে চান না এমন খরচগুলি এড়ানোর পক্ষে এটি নিরাপদ ভাষা হিসাবে ব্যবহার করার চেষ্টা করার প্রয়োজন হয় না other অন্য কিছুর বিনিময় প্রস্তাবিত ব্যবহার ঝুঁকিপূর্ণ পয়েন্টার এবং অবৈধ পুনরাবৃত্তির মতো জিনিসগুলি থেকে আপনাকে রক্ষা করার চেষ্টা করছে না, তাই কথা বলতে (অন্যথায় আমাদের ব্যবহার করতে উত্সাহিত করা হবে)shared_ptr
সমস্ত জায়গা জুড়ে, যা স্ট্রস্ট্রুপ তীব্র বিরোধিতা করে)। এটি কোনও বিষয় যখন সঠিকভাবে মুক্ত / মুক্তি / ধ্বংস / আনলক / পরিষ্কার করতে ব্যর্থতা থেকে রক্ষা করার চেষ্টা করছে throws
।