আপনার প্রশ্নটি দৃ as়তার সাথে জানিয়েছে যে "ব্যতিক্রম-নিরাপদ কোড লেখা খুব শক্ত"। আমি প্রথমে আপনার প্রশ্নের উত্তর দেব, এবং তারপরে, তাদের পিছনে লুকানো প্রশ্নের উত্তর দেব।
প্রশ্নের উত্তর দিচ্ছি
আপনি কি সত্যিই ব্যতিক্রম নিরাপদ কোড লেখেন?
অবশ্যই আমি করবো.
এই কারণে জাভা একটি সি ++ প্রোগ্রামার (RAII শব্দার্থবিদ্যা অভাব) আমার তার আবেদন অনেক হারিয়ে গেছে, কিন্তু আমি digressing করছি: এটি একটি সি ++ প্রশ্ন।
এটি এসটিএল বা বুস্ট কোড সহ যখন আপনার কাজ করার দরকার হয় তখন এটি প্রয়োজনীয়। উদাহরণস্বরূপ, সি ++ থ্রেড ( boost::thread
বা std::thread
) করুণভাবে প্রস্থান করার জন্য একটি ব্যতিক্রম ছুঁড়ে ফেলবে।
আপনি কি নিশ্চিত যে আপনার শেষ "উত্পাদন প্রস্তুত" কোডটি ব্যতিক্রম নিরাপদ?
আপনি কি নিশ্চিত হতে পারেন, এটি যে?
ব্যতিক্রম-নিরাপদ কোড লেখা বাগ-ফ্রি কোড লেখার মতো।
আপনার কোডটি ব্যতিক্রম নিরাপদ কিনা আপনি 100% নিশ্চিত হতে পারবেন না। তবে তারপরে, আপনি সুপরিচিত নিদর্শনগুলি ব্যবহার করে এবং সুপরিচিত অ্যান্টি-প্যাটার্নগুলি এড়িয়ে চলার জন্য এটির জন্য প্রচেষ্টা করছেন।
আপনি কি জানেন এবং / অথবা আসলে কাজ করে এমন বিকল্পগুলি ব্যবহার করেন?
আছে কোন সি টেকসই বিকল্প ++, (অর্থাত আপনি সি এবং এড়ানোর সি ++ লাইব্রেরি, সেইসাথে উইন্ডোজ Seh মত বাহ্যিক চমকের ফিরে প্রত্যাবর্তন করতে হবে)।
ব্যতিক্রম নিরাপদ কোড লেখা
ব্যতিক্রম নিরাপদ কোড লিখতে, আপনাকে অবশ্যই প্রথমে জানতে হবে যে প্রতিটি নির্দেশ আপনি কী ব্যতিক্রম সুরক্ষা লিখেছেন of
উদাহরণস্বরূপ, একটি new
ব্যতিক্রম ছুঁড়ে ফেলতে পারে তবে একটি অন্তর্নির্মিত (যেমন কোনও আন্ত, বা পয়েন্টার) নির্ধারণ করা ব্যর্থ হবে না। একটি অদলবদল কখনই ব্যর্থ হবে না (কখনও কোনও ছোঁড়ার স্ব্যাপটি লিখবেন না), একটি std::list::push_back
নিক্ষেপ করতে পারে ...
ব্যতিক্রম গ্যারান্টি
প্রথমটি বুঝতে হবে যে আপনাকে অবশ্যই আপনার সমস্ত কার্য দ্বারা প্রদত্ত ব্যতিক্রম গ্যারান্টিটি মূল্যায়ন করতে সক্ষম হতে হবে:
- কোনটি নয় : আপনার কোডটি কখনই অফার করা উচিত নয়। এই কোডটি সবকিছু ফাঁস হয়ে যাবে এবং ফেলে দেওয়া প্রথম ব্যতিক্রমে ভেঙে যাবে।
- বুনিয়াদি : এটি আপনাকে অবশ্যই খুব স্বল্পতম অফারে অবশ্যই গ্যারান্টি দেয়, এটি হ'ল যদি কোনও ব্যতিক্রম ছুঁড়ে দেওয়া হয় তবে কোনও উত্স ফাঁস হয় না এবং সমস্ত বস্তু এখনও সম্পূর্ণ থাকে না
- শক্তিশালী : প্রক্রিয়াজাতকরণটি সফল হয়, বা একটি ব্যতিক্রম ছুঁড়ে ফেলবে, তবে যদি এটি ছুড়ে যায়, তবে ডেটা একই অবস্থায় থাকবে যেন প্রক্রিয়া শুরু হয় নি (এটি সি ++ এ একটি ট্রানজেকশনাল শক্তি দেয়)
- nothrow / nofail : প্রক্রিয়াটি সফল হবে।
কোড উদাহরণ
নিম্নলিখিত কোডটি সঠিক সি ++ এর মতো বলে মনে হচ্ছে তবে সত্য, এটি "কিছুই নয়" গ্যারান্টি সরবরাহ করে এবং সুতরাং এটি সঠিক নয়:
void doSomething(T & t)
{
if(std::numeric_limits<int>::max() > t.integer) // 1. nothrow/nofail
t.integer += 1 ; // 1'. nothrow/nofail
X * x = new X() ; // 2. basic : can throw with new and X constructor
t.list.push_back(x) ; // 3. strong : can throw
x->doSomethingThatCanThrow() ; // 4. basic : can throw
}
এই ধরণের বিশ্লেষণকে মাথায় রেখে আমি আমার সমস্ত কোড লিখি।
প্রদত্ত সর্বনিম্ন গ্যারান্টিটি বেসিক, তবে তারপরে, প্রতিটি নির্দেশের ক্রম পুরো ফাংশনটিকে "কিছুই না" করে তোলে, কারণ যদি 3 টি ছুড়ে, এক্স ফাঁস হয়ে যায়।
প্রথম কাজটি হ'ল ফাংশনটিকে "বেসিক" করা, এটি এক্সটিকে স্মার্ট পয়েন্টারে রেখে দিবে যতক্ষণ না এটি নিরাপদে তালিকার মালিকানাযুক্ত:
void doSomething(T & t)
{
if(std::numeric_limits<int>::max() > t.integer) // 1. nothrow/nofail
t.integer += 1 ; // 1'. nothrow/nofail
std::auto_ptr<X> x(new X()) ; // 2. basic : can throw with new and X constructor
X * px = x.get() ; // 2'. nothrow/nofail
t.list.push_back(px) ; // 3. strong : can throw
x.release() ; // 3'. nothrow/nofail
px->doSomethingThatCanThrow() ; // 4. basic : can throw
}
এখন, আমাদের কোড একটি "বেসিক" গ্যারান্টি দেয়। কিছুই ফাঁস হবে না এবং সমস্ত বস্তু সঠিক অবস্থায় থাকবে। তবে আমরা আরও অফার করতে পারি, তা হ'ল দৃ guarantee় গ্যারান্টি। এই যেখানে এটি করতে ব্যয়বহুল হয়ে এবং কেন এই হল না সব সি ++ কোড শক্তিশালী। চল এটা চেষ্টা করি:
void doSomething(T & t)
{
// we create "x"
std::auto_ptr<X> x(new X()) ; // 1. basic : can throw with new and X constructor
X * px = x.get() ; // 2. nothrow/nofail
px->doSomethingThatCanThrow() ; // 3. basic : can throw
// we copy the original container to avoid changing it
T t2(t) ; // 4. strong : can throw with T copy-constructor
// we put "x" in the copied container
t2.list.push_back(px) ; // 5. strong : can throw
x.release() ; // 6. nothrow/nofail
if(std::numeric_limits<int>::max() > t2.integer) // 7. nothrow/nofail
t2.integer += 1 ; // 7'. nothrow/nofail
// we swap both containers
t.swap(t2) ; // 8. nothrow/nofail
}
আমরা প্রথমে ক্রিয়াকলাপটি অর্ডার করেছি, প্রথমে X
এটির সঠিক মান নির্ধারণ এবং সেট করা। যদি কোনও অপারেশন ব্যর্থ হয়, তবে t
তা সংশোধিত হয় না, সুতরাং, অপারেশন 1 থেকে 3টিকে "শক্তিশালী" হিসাবে বিবেচনা করা যেতে পারে: যদি t
কোনও কিছু ছোঁড়ে, সংশোধিত হয় না এবং X
ফাঁস হয় না কারণ এটি স্মার্ট পয়েন্টারটির মালিকানাধীন।
এর পরে, আমরা একটি অনুলিপি তৈরি t2
এর t
7., এবং অপারেশন 4 থেকে এই কপি কাজ কিছু ছোঁড়ার পারেন, t2
রুপান্তরিত করা হয়েছে, কিন্তু তারপর, t
তারপরেও অরিজিনাল হয়। আমরা এখনও দৃ strong় গ্যারান্টি অফার।
তারপরে, আমরা অদলবদল t
এবং t2
। অদলবদল ক্রিয়াকলাপগুলি সি ++ তে নথ্র হওয়া উচিত, সুতরাং আসুন আশা করি আপনি T
যে স্বাপের জন্য লিখেছেন তা নোহ্রো (যদি তা না হয় তবে এটি পুনরায় লিখুন যাতে এটি নোরো হয়)।
সুতরাং, আমরা যদি ফাংশনটির শেষে পৌঁছে যাই, তবে সমস্ত কিছুই t
সাফল্য পেয়েছে (রিটার্নের ধরণের দরকার নেই) এবং এর ব্যতীত মূল্য রয়েছে। যদি এটি ব্যর্থ হয় তবে t
তার এখনও এর মূল মূল্য রয়েছে।
এখন, দৃ guarantee় গ্যারান্টি সরবরাহ করা ব্যয়বহুল হতে পারে, সুতরাং আপনার সমস্ত কোডের দৃ guarantee় গ্যারান্টি দেওয়ার চেষ্টা করবেন না, তবে আপনি যদি ব্যয় ছাড়াই এটি করতে পারেন (এবং সি ++ ইনলাইনিং এবং অন্যান্য অপ্টিমাইজেশন সমস্ত কোডকে ব্যয়বহুল করে তুলতে পারে) , তাহলে এটা করো. ফাংশন ব্যবহারকারী এটির জন্য আপনাকে ধন্যবাদ জানাবে।
উপসংহার
ব্যতিক্রম-নিরাপদ কোড লিখতে কিছুটা অভ্যাস লাগে habit আপনি যে প্রতিটি নির্দেশনা ব্যবহার করবেন তার দ্বারা প্রদত্ত গ্যারান্টিটি মূল্যায়ন করতে হবে এবং তারপরে আপনাকে নির্দেশাবলীর তালিকা দ্বারা প্রদত্ত গ্যারান্টিটি মূল্যায়ন করতে হবে।
অবশ্যই, সি ++ সংকলক গ্যারান্টিটি ব্যাক আপ করবে না (আমার কোড অনুসারে, আমি গ্যারান্টিটি একটি @ ওয়ার্নিং ডোজিজেন ট্যাগ হিসাবে দিচ্ছি), যা অত্যন্ত দুঃখজনক, তবে এটি আপনাকে ব্যতিক্রম-নিরাপদ কোড লেখার চেষ্টা থেকে বিরত রাখা উচিত নয়।
সাধারণ ব্যর্থতা বনাম বাগ
কোনও প্রোগ্রামার কীভাবে গ্যারান্টি দিতে পারে যে কোনও ব্যর্থ ফাংশন সর্বদা সফল হবে? সর্বোপরি, ফাংশনে একটি বাগ থাকতে পারে।
এটা সত্য. এই ব্যতিক্রম গ্যারান্টিগুলি বাগ-মুক্ত কোডের মাধ্যমে প্রস্তাবিত হওয়ার কথা। তবে, যে কোনও ভাষায়, কোনও ফাংশন কল করার বিষয়টি ধরে ফাংশনটি বাগ-মুক্ত। কোনও বুদ্ধিমান কোড এর বাগ থাকার সম্ভাবনা থেকে নিজেকে রক্ষা করে না। কোডটি আপনার পক্ষে সবচেয়ে ভাল লিখুন এবং তারপরে, এটি বাগ-মুক্ত বলে অনুমান সহ গ্যারান্টিটি দিন। এবং যদি কোনও বাগ থাকে তবে এটি সংশোধন করুন।
ব্যতিক্রম ব্যতিক্রমী প্রক্রিয়াকরণ ব্যর্থতার জন্য, কোড বাগের জন্য নয়।
শেষ কথা
এখন, প্রশ্নটি "এটি কি এটি মূল্যবান?"
অবশ্যই এটা. ফাংশনটি ব্যর্থ হবে না জেনে একটি "নোহ্রো / নো-ফেইল" ফাংশন থাকা একটি দুর্দান্ত আশ্বাস। একই "শক্তিশালী" ফাংশনের জন্যও বলা যেতে পারে, যা আপনাকে লেনদেনমূলক শব্দার্থবিজ্ঞানের সাথে কোড লিখতে সক্ষম করে, যেমন ডাটাবেসগুলি, কমিট / রোলব্যাক বৈশিষ্ট্য সহ, কমিটকে কোডটির সাধারণ সম্পাদন করা হয়, ব্যতিক্রমকে রোলব্যাক হিসাবে ছুঁড়ে দেওয়া হয়।
তারপরে, "বেসিক" হ'ল আপনার অফার করা উচিত খুব কম গ্যারান্টি। সি ++ হ'ল একটি অত্যন্ত শক্তিশালী ভাষা, এর স্কোপগুলি সহ, আপনাকে কোনও উত্স ফাঁস এড়াতে সক্ষম করে তোলে (এমন কোনও জিনিস যা কোনও আবর্জনা সংগ্রহকারীকে ডাটাবেস, সংযোগ বা ফাইল হ্যান্ডলগুলির জন্য অফার করতে অসুবিধা হবে)।
সুতরাং, যতদূর আমি এটা দেখতে হিসেবে, এটা হয় এটা মূল্য।
2010-01-29 সম্পাদনা করুন: নিক্ষেপ অদলবদল সম্পর্কে
নোবার একটি মন্তব্য করেছেন যে আমি বিশ্বাস করি, এটি যথেষ্ট প্রাসঙ্গিক, কারণ এটি "আপনি কীভাবে ব্যতিক্রম নিরাপদ কোড লিখবেন" এর অংশ:
- [আমি] একটি অদলবদল কখনও ব্যর্থ হবে না (এমনকি একটি ছোঁড়া স্ব্যাপটি লিখবেন না)
- [নোবার] এটি কাস্টম-লিখিত
swap()
ফাংশনগুলির জন্য একটি ভাল সুপারিশ । তবে এটি লক্ষ করা উচিত std::swap()
যে এটি অভ্যন্তরীণভাবে ব্যবহৃত অপারেশনের ভিত্তিতে ব্যর্থ হতে পারে
ডিফল্টটি std::swap
অনুলিপি এবং অ্যাসাইনমেন্ট তৈরি করবে যা কিছু বস্তুর জন্য নিক্ষেপ করতে পারে। সুতরাং, ডিফল্ট অদলবদল নিক্ষেপ করতে পারে, হয় আপনার শ্রেণীর জন্য এমনকি এসটিএল ক্লাসের জন্যও ব্যবহৃত হয়। যতদুর C ++ -এর মান সংশ্লিষ্ট হয়, জন্য swap 'র অপারেশন vector
, deque
এবং list
, নিক্ষেপ করা হবে না যেহেতু এটি জন্য পারে map
যদি তুলনা functor কপি নির্মাণ (দেখুন উপর নিক্ষেপ করতে পারেন দ্য সি ++ ভাষা, বিশেষ সংস্করণ, পরিশিষ্ট E, E.4.3 প্রোগ্রামিং .স্বপ )।
ভেক্টরের অদলবদলটির ভিজ্যুয়াল সি ++ ২০০৮ বাস্তবায়নের দিকে তাকালে, ভেক্টরের অদলবদল দুটি ভেক্টরের একই বরাদ্দকারীর (যেমন, সাধারণ কেস) থাকে না তবে তারা পৃথকর বরাদ্দকারী থাকলে অনুলিপিগুলি তৈরি করবে। এবং এইভাবে, আমি ধরে নিচ্ছি যে এটি এই শেষ ক্ষেত্রে ফেলে দিতে পারে।
সুতরাং, মূল পাঠ্যটি এখনও ধারণ করে: কখনও কোনও নিক্ষেপকারী অদলবদল লিখবেন না, তবে নোবারের মন্তব্য অবশ্যই মনে রাখতে হবে: আপনি যে জিনিসগুলি স্যুপ করছেন সেগুলিতে একটি নিক্ষেপকারী অদলবদল রয়েছে তা নিশ্চিত হয়ে নিন।
2011-11-06 সম্পাদনা করুন: আকর্ষণীয় নিবন্ধ
ডেভ আব্রাহামস , যিনি আমাদের বুনিয়াদি / শক্তিশালী / নোট্রো গ্যারান্টি দিয়েছেন , একটি নিবন্ধে এসটিএল ব্যতিক্রমকে নিরাপদ করার বিষয়ে তাঁর অভিজ্ঞতার বর্ণনা দিয়েছেন:
http://www.boost.org/community/exception_safety.html
7th ম পয়েন্টটি দেখুন (ব্যতিক্রম-সুরক্ষার জন্য অটোমেটেড টেস্টিং), যেখানে তিনি প্রতিটি কেস পরীক্ষা করা হচ্ছে না তা নিশ্চিত করতে স্বয়ংক্রিয় ইউনিট পরীক্ষার উপর নির্ভর করে। আমি অনুমান করি যে এই অংশটি প্রশ্ন লেখকের " আপনি কি এমনকি নিশ্চিত হতে পারেন যে এটি? " একটি দুর্দান্ত উত্তর ।
2013-05-31 সম্পাদনা করুন: দিয়ানোদার থেকে মন্তব্য
t.integer += 1;
গ্যারান্টি ছাড়াই যে ওভারফ্লোটি ব্যতিক্রম নিরাপদ হবে না, এবং বাস্তবে প্রযুক্তিগতভাবে ইউবিকে ডাকতে পারে! (স্বাক্ষরিত ওভারফ্লো হ'ল ইউবি: সি ++ 11 5/4 "যদি কোনও অভিব্যক্তির মূল্যায়নের সময়, ফলাফলটি গাণিতিকভাবে সংজ্ঞায়িত না হয় বা তার ধরণের জন্য উপস্থাপনযোগ্য মানগুলির পরিসীমাতে না হয় তবে আচরণটি অপরিবর্তিত থাকে।") নোট করুন যে স্বাক্ষরিত পূর্ণসংখ্যা ওভারফ্লো হয় না, তবে তাদের গণনা সমতুল্য শ্রেণির 2 ^ # বিটগুলিতে করুন।
ডিওনাডার নিম্নলিখিত লাইনের উল্লেখ করছেন, যা প্রকৃতপক্ষে অপরিবর্তিত আচরণ করেছে has
t.integer += 1 ; // 1. nothrow/nofail
এখানে সমাধানটি হল যাচাইয়ের আগে পূর্ণসংখ্যাটি ইতিমধ্যে তার সর্বাধিক মানটিতে (ব্যবহার করা std::numeric_limits<T>::max()
) হয় কিনা তা যাচাই করা ।
আমার ত্রুটিটি "সাধারণ ব্যর্থতা বনাম বাগ" বিভাগে চলে যাবে, এটি একটি বাগ। এটি যুক্তিটিকে অকার্যকর করে না, এবং এর অর্থ এই নয় যে ব্যতিক্রম-নিরাপদ কোডটি অকার্যকর কারণ এটি অর্জন করা অসম্ভব। আপনি কম্পিউটার স্যুইচিং অফ, বা সংকলক বাগগুলি, এমনকি আপনার বাগগুলি, বা অন্যান্য ত্রুটিগুলির বিরুদ্ধে নিজেকে রক্ষা করতে পারবেন না। আপনি পরিপূর্ণতা অর্জন করতে পারবেন না, তবে আপনি যতটা সম্ভব সম্ভব কাছাকাছি যাওয়ার চেষ্টা করতে পারেন।
আমি দিওনাদারের মন্তব্যে মাথায় রেখে কোডটি সংশোধন করেছি।