উত্তর:
না, সি ++ 'অবশেষে' ব্লকগুলিকে সমর্থন করে না। "রিসোর্স অধিগ্রহণ হল সূচনা" - A: কারণ সি ++ পরিবর্তে RAII সমর্থন করে দরিদ্র নাম † সত্যিই একটি দরকারী ধারণা জন্য।
ধারণাটি হ'ল কোনও বস্তুর ডেস্ট্রাক্টর সম্পদ মুক্ত করার জন্য দায়বদ্ধ। যখন অবজেক্টটির স্বয়ংক্রিয় স্টোরেজ সময়কাল থাকে, তখন অবজেক্টের ডেস্ট্রাক্টরকে ডাকা হবে যখন এটি তৈরি করা ব্লকটি বেরিয়ে আসে - এমনকি যখন সেই ব্লকটি ব্যতিক্রমের উপস্থিতিতে উপস্থিত থাকে। বিষয়টির ব্যাখ্যা এখানে বর্জন স্ট্রস্ট্রুপের দেওয়া আছে ।
RAII এর একটি সাধারণ ব্যবহার একটি নিঃশব্দটিকে লক করছে:
// A class with implements RAII
class lock
{
mutex &m_;
public:
lock(mutex &m)
: m_(m)
{
m.acquire();
}
~lock()
{
m_.release();
}
};
// A class which uses 'mutex' and 'lock' objects
class foo
{
mutex mutex_; // mutex for locking 'foo' object
public:
void bar()
{
lock scopeLock(mutex_); // lock object.
foobar(); // an operation which may throw an exception
// scopeLock will be destructed even if an exception
// occurs, which will release the mutex and allow
// other functions to lock the object and run.
}
};
RAII অন্যান্য শ্রেণীর সদস্য হিসাবেও অবজেক্টগুলি ব্যবহার করা সহজ করে। মালিকানাধীন শ্রেণি 'ধ্বংস হয়ে গেলে, আরআইআইআই ক্লাস দ্বারা পরিচালিত সংস্থানটি প্রকাশিত হয় কারণ রায়-পরিচালিত শ্রেণীর ধ্বংসকারীকে ফলাফল হিসাবে ডেকে আনে। এর অর্থ হ'ল আপনি যখন সংস্থানগুলি পরিচালনা করে এমন কোনও শ্রেণীর সমস্ত সদস্যের জন্য আরআইআই ব্যবহার করেন, আপনি খুব সাধারণ, সম্ভবত এমনকি ডিফল্ট, মালিক শ্রেণীর জন্য ডেস্ট্রাক্টর ব্যবহার করে চলে যেতে পারেন কারণ এর সদস্যপদটির আধ্যাত্মিক জীবনকাল ম্যানুয়ালি ম্যানেজ করার দরকার নেই doesn't । (এটি নির্দেশ করার জন্য মাইক বিকে ধন্যবাদ ))
সি # বা ভিবি.এনইটি সহ ফ্যামিলিয়ারগুলির জন্য, আপনি সনাক্ত করতে পারেন যে RAII আইডিজিপোজযোগ্য এবং 'ব্যবহার' বিবৃতি ব্যবহার করে নেট নেট নির্বাহী ধ্বংসের সমান । প্রকৃতপক্ষে, দুটি পদ্ধতি খুব একই রকম। মূল পার্থক্য হ'ল RAII স্মৃতি সহ যেকোন ধরণের সংস্থানকে নির্বিচারে প্রকাশ করবে। .NET (এমনকি। নেট ভাষা সি ++ / সিএলআই) তে আইডিস্পোজেবল বাস্তবায়ন করার সময়, স্মৃতি ছাড়া স্মৃতি বাদ দিয়ে সংস্থানগুলি ছেড়ে দেওয়া হবে। .NET- এ, মেমরিটি নির্বিচারে প্রকাশিত হয় না; মেমরি কেবল আবর্জনা সংগ্রহের চক্রের সময় প্রকাশিত হয়।
† কিছু লোক বিশ্বাস করে যে "ধ্বংস হ'ল রিসোর্স রিজিকুইজমেন্ট" এটি রাই আইআইওমের আরও সঠিক নাম।
সি ++ এ শেষ অবধি নেই RAII এর কারণে প্রয়োজন ।
RAII অবজেক্টের ব্যবহারকারী থেকে অবজেক্ট সুরক্ষার দায়িত্বটিকে অবজেক্টটির ডিজাইনার (এবং প্রয়োগকারী) এর দিকে নিয়ে যায়। আমি তর্ক করব এটি সঠিক জায়গা কারণ আপনার কেবলমাত্র ব্যতিক্রমী সুরক্ষা একবারে নেওয়া দরকার (নকশা / প্রয়োগের ক্ষেত্রে)। অবশেষে ব্যবহার করে আপনি প্রতিবার কোনও জিনিস ব্যবহার করার সময় ব্যতিক্রমী সুরক্ষাটি সঠিকভাবে নেওয়া দরকার correct
আইএমও কোডটি আরও সুন্দর দেখাচ্ছে (নীচে দেখুন))
উদাহরণ:
একটি ডাটাবেস অবজেক্ট। ডিবি সংযোগটি ব্যবহার করা হয়েছে তা নিশ্চিত করার জন্য এটি অবশ্যই খোলা এবং বন্ধ করতে হবে। RAII ব্যবহার করে এটি কনস্ট্রাক্টর / ডেস্ট্রাক্টরে করা যেতে পারে।
void someFunc()
{
DB db("DBDesciptionString");
// Use the db object.
} // db goes out of scope and destructor closes the connection.
// This happens even in the presence of exceptions.
RAII এর ব্যবহার একটি ডিবি অবজেক্ট সঠিকভাবে ব্যবহার করা খুব সহজ করে। আমরা যেভাবে চেষ্টা করি না কেন এবং অপব্যবহার করি না কেন ডিবি অবজেক্টটি ডিস্ট্রাক্টর ব্যবহার করে সঠিকভাবে নিজেকে বন্ধ করে দেবে।
void someFunc()
{
DB db = new DB("DBDesciptionString");
try
{
// Use the db object.
}
finally
{
// Can not rely on finaliser.
// So we must explicitly close the connection.
try
{
db.close();
}
catch(Throwable e)
{
/* Ignore */
// Make sure not to throw exception if one is already propagating.
}
}
}
অবশেষে ব্যবহার করার সময় অবজেক্টটির সঠিক ব্যবহার অবজেক্টের ব্যবহারকারীর কাছে অর্পণ করা হয়। অর্থাত সঠিকভাবে ডিবি সংযোগ বন্ধ করা অবজেক্ট ব্যবহারকারীর দায়িত্ব। এখন আপনি যুক্তি দিতে পারেন যে এটি চূড়ান্তকরণে করা যেতে পারে, তবে সংস্থানগুলিতে সীমাবদ্ধতা বা অন্যান্য সীমাবদ্ধতা থাকতে পারে এবং সুতরাং আপনি সাধারণত অবজেক্টের মুক্তি নিয়ন্ত্রণ করতে চান এবং আবর্জনা সংগ্রাহকের অ-সংঘবদ্ধ আচরণের উপর নির্ভর করতে পারেন না।
এছাড়াও এটি একটি সহজ উদাহরণ।
যখন আপনার একাধিক সংস্থান রয়েছে যা কোড প্রকাশ করতে হবে জটিল হতে পারে।
আরও বিশদ বিশ্লেষণ এখানে পাওয়া যাবে: http://accu.org/index.php/journals/236
// Make sure not to throw exception if one is already propagating.
সি ++ ডিসস্ট্রাক্টরদের পক্ষে এই কারণেই ব্যতিক্রম না ছড়ানো উচিত।
RAII সাধারণত ভাল, তবে আপনি সহজেই সি ++ এ শেষ অবধি শব্দার্থক থাকতে পারেন । একটি ক্ষুদ্র পরিমাণের কোড ব্যবহার করা।
এছাড়াও, সি ++ মূল নির্দেশিকা শেষ পর্যন্ত দেয়।
এখানে জিএসএল মাইক্রোসফ্ট বাস্তবায়নের একটি লিঙ্ক এবং মার্টিন মোইন প্রয়োগের একটি লিঙ্ক রয়েছে
বাজর্ন স্ট্রাস্ট্রপ একাধিকবার বলেছিল যে জিএসএলে যা আছে তার সবশেষে স্ট্যান্ডার্ডে যাওয়ার অর্থ। সুতরাং অবশেষে এটি ব্যবহারের ভবিষ্যত-প্রমাণ উপায় হওয়া উচিত ।
আপনি চাইলে সহজেই নিজেকে বাস্তবায়ন করতে পারেন, পড়া চালিয়ে যান।
সি ++ এ 11 আরআইআই এবং ল্যাম্বডাস শেষ পর্যন্ত একটি সাধারণ তৈরি করতে দেয়:
namespace detail { //adapt to your "private" namespace
template <typename F>
struct FinalAction {
FinalAction(F f) : clean_{f} {}
~FinalAction() { if(enabled_) clean_(); }
void disable() { enabled_ = false; };
private:
F clean_;
bool enabled_{true}; }; }
template <typename F>
detail::FinalAction<F> finally(F f) {
return detail::FinalAction<F>(f); }
ব্যবহারের উদাহরণ:
#include <iostream>
int main() {
int* a = new int;
auto delete_a = finally([a] { delete a; std::cout << "leaving the block, deleting a!\n"; });
std::cout << "doing something ...\n"; }
আউটপুট হবে:
doing something...
leaving the block, deleting a!
ব্যক্তিগতভাবে আমি একটি সি ++ প্রোগ্রামে পসেক্স ফাইল ডেস্ক্রিপ্টরটি বন্ধ করার জন্য এটি কয়েকবার ব্যবহার করেছি।
একটি রিয়েল ক্লাস থাকা যা রিসোর্সগুলি পরিচালনা করে এবং তাই কোনও প্রকার ফাঁস এড়িয়ে যায় সাধারণত ভাল তবে এটি শেষ পর্যন্ত এমন ক্ষেত্রে কার্যকর যেখানে শ্রেণি তৈরি করা ওভারকিলের মতো শোনাচ্ছে।
এছাড়াও, আমি অন্য ভাষার চেয়ে এটি শেষ পর্যন্ত পছন্দ করি কারণ প্রাকৃতিকভাবে ব্যবহৃত হলে আপনি প্রারম্ভিক কোডটির নিকটবর্তী সমাপ্তি কোডটি লিখেন (আমার উদাহরণে নতুন এবং মুছুন ) এবং ধ্বংসটি সি ++ এর মতো যথারীতি লিফোর ক্রমে নির্মাণ অনুসরণ করে। একমাত্র ক্ষতি হ'ল আপনি একটি অটো ভেরিয়েবল পাবেন যা আপনি সত্যই ব্যবহার করেন না এবং ল্যাম্বদা সিনট্যাক্স এটিকে কিছুটা গোলমাল করে তোলে (আমার উদাহরণে চতুর্থ লাইনে কেবল অবশেষে শব্দটি এবং ডানদিকে block block-ব্লক অর্থবহ, বিশ্রামটি মূলত গোলমাল)।
আরেকটি উদাহরণ:
[...]
auto precision = std::cout.precision();
auto set_precision_back = finally( [precision, &std::cout]() { std::cout << std::setprecision(precision); } );
std::cout << std::setprecision(3);
নিষ্ক্রিয় যদি সদস্য দরকারী পরিশেষে শুধুমাত্র ব্যর্থতার ক্ষেত্রে বলা হবে। উদাহরণস্বরূপ, আপনাকে তিনটি ভিন্ন ধারক মধ্যে একটি বিষয় অনুলিপি করতে হবে, প্রতিটি অনুলিপি পূর্বাবস্থায় ফেলার জন্য আপনি শেষ পর্যন্ত সেটআপ করতে পারেন এবং সমস্ত অনুলিপি সফল হওয়ার পরে অক্ষম করতে পারেন। এটি করা, যদি ধ্বংসটি ছুঁতে না পারে তবে আপনি দৃ strong় গ্যারান্টি নিশ্চিত করেন।
অক্ষম উদাহরণ:
//strong guarantee
void copy_to_all(BIGobj const& a) {
first_.push_back(a);
auto undo_first_push = finally([first_&] { first_.pop_back(); });
second_.push_back(a);
auto undo_second_push = finally([second_&] { second_.pop_back(); });
third_.push_back(a);
//no necessary, put just to make easier to add containers in the future
auto undo_third_push = finally([third_&] { third_.pop_back(); });
undo_first_push.disable();
undo_second_push.disable();
undo_third_push.disable(); }
আপনি যদি সি ++ 11 ব্যবহার করতে না পারেন তবে আপনার অবশেষে থাকতে পারে তবে কোডটি আরও কিছুটা দীর্ঘ বাতাসে পরিণত হয়। কেবলমাত্র একজন কনস্ট্রাক্টর এবং ডেস্ট্রাক্টর দিয়ে একটি স্ট্রাক্ট সংজ্ঞায়িত করুন, নির্মাণকারী প্রয়োজনীয় যে কোনও বিষয়ে রেফারেন্স নেন এবং ডেস্ট্রাক্টর আপনার প্রয়োজনীয় ক্রিয়াগুলি করেন। এটি ল্যাম্বডা ম্যানুয়ালি করে মূলত যা করে।
#include <iostream>
int main() {
int* a = new int;
struct Delete_a_t {
Delete_a_t(int* p) : p_(p) {}
~Delete_a_t() { delete p_; std::cout << "leaving the block, deleting a!\n"; }
int* p_;
} delete_a(a);
std::cout << "doing something ...\n"; }
FinalAction
মূলত জনপ্রিয় ScopeGuard
আইডিয়াম হিসাবে একই , শুধুমাত্র একটি ভিন্ন নাম দিয়ে।
স্ট্যাক-ভিত্তিক অবজেক্টের সাহায্যে সাফাই সহজ করা ছাড়াও, RAII এছাড়াও দরকারী কারণ একই জিনিস 'স্বয়ংক্রিয়' ক্লিন আপ ঘটে যখন বস্তুটি অন্য শ্রেণীর সদস্য হয়। মালিকানাধীন শ্রেণিটি ধ্বংস হয়ে গেলে, আরএআইআই ক্লাস দ্বারা পরিচালিত সংস্থানটি পরিষ্কার হয়ে যায় কারণ class শ্রেণীর জন্য দোসর ফলাফল হিসাবে ডেকে আনে।
এর অর্থ হ'ল আপনি যখন আরএআইআই নির্বান পৌঁছে যান এবং ক্লাসে থাকা সমস্ত সদস্যরা আরআইআইআই ব্যবহার করে (স্মার্ট পয়েন্টারগুলির মতো), আপনি মালিক শ্রেণীর জন্য খুব সাধারণ (সম্ভবত এমনকি ডিফল্ট) ডর্টর নিয়েও চলে যেতে পারেন যেহেতু এটি নিজে নিজে পরিচালনা করার দরকার নেই need সদস্য সংস্থান জীবনকাল।
কেন এমন কি কেন যে ম্যানেজ করা ভাষাগুলি যে কোনও উপায়ে আবর্জনা সংগ্রহকারী কর্তৃক স্বয়ংক্রিয়ভাবে স্বয়ংক্রিয়ভাবে অবনমিত হওয়া সত্ত্বেও অবশেষে ব্লক সরবরাহ করে?
আসলে, আবর্জনা সংগ্রহকারীদের উপর ভিত্তি করে ভাষাগুলির আরও "অবশেষে" প্রয়োজন need কোনও আবর্জনা সংগ্রহকারী সময় মতো আপনার জিনিসগুলি ধ্বংস করে না, তাই এটি অ-স্মৃতি সম্পর্কিত সমস্যাগুলি সঠিকভাবে পরিষ্কার করার উপর নির্ভর করা যায় না।
গতিশীলভাবে বরাদ্দকৃত ডেটার ক্ষেত্রে, অনেকে তর্ক করবে যে আপনার স্মার্ট-পয়েন্টার ব্যবহার করা উচিত।
যাহোক...
RAII অবজেক্ট সুরক্ষার দায়িত্বটি অবজেক্টের ব্যবহারকারীর কাছ থেকে ডিজাইনারের দিকে নিয়ে যায়
দুঃখের বিষয় এটি নিজস্ব পতন। পুরানো সি প্রোগ্রামিং অভ্যাস হার্ড মারা যায়। আপনি যখন সি বা খুব সি স্টাইলে লেখা একটি লাইব্রেরি ব্যবহার করছেন তখন RAII ব্যবহার করা হত না। পুরো এপিআই এর সম্মুখ-প্রান্তটি পুনরায় লেখার সংক্ষিপ্ততা, আপনার সাথে কাজ করতে হবে এটিই। তারপরে "অবশেষে" অভাব সত্যিই কামড় দেয়।
CleanupFailedException
। আরআইআইআই ব্যবহার করে এই জাতীয় ফলাফল অর্জনের জন্য কি কোনও প্রশংসনীয় উপায় আছে?
SomeObject.DoSomething()
পদ্ধতি কল করে এটি জানতে চায় যে এটি (1) সফল হয়েছে কিনা, (2) কোনও পার্শ্ব-প্রতিক্রিয়া ছাড়াই ব্যর্থ হয়েছে , (3) পার্শ্ব-প্রতিক্রিয়াতে ব্যর্থ কলার সাথে মোকাবিলা করার জন্য প্রস্তুত , বা (4) পার্শ্ব প্রতিক্রিয়া নিয়ে ব্যর্থ কলার সহ্য করতে পারে না। কেবলমাত্র আহ্বায়ক জানতে পারে যে এটি কোন পরিস্থিতিতে কী কী পরিস্থিতি মোকাবেলা করতে পারে এবং কী করতে পারে না; কলারের কী দরকার তা পরিস্থিতিটি কী তা জানার উপায়। এটি খুব খারাপ যে কোনও ব্যতিক্রম সম্পর্কে সর্বাধিক গুরুত্বপূর্ণ তথ্য সরবরাহের জন্য কোনও মানক ব্যবস্থা নেই।
সি ++ 11 ল্যাম্বদা ফাংশন ব্যবহার করে অন্য একটি "অবশেষে" ব্লক ইমুলেশন
template <typename TCode, typename TFinallyCode>
inline void with_finally(const TCode &code, const TFinallyCode &finally_code)
{
try
{
code();
}
catch (...)
{
try
{
finally_code();
}
catch (...) // Maybe stupid check that finally_code mustn't throw.
{
std::terminate();
}
throw;
}
finally_code();
}
আসুন আশা করি সংকলক উপরের কোডটি অনুকূলিত করবে।
এখন আমরা এই জাতীয় কোড লিখতে পারি:
with_finally(
[&]()
{
try
{
// Doing some stuff that may throw an exception
}
catch (const exception1 &)
{
// Handling first class of exceptions
}
catch (const exception2 &)
{
// Handling another class of exceptions
}
// Some classes of exceptions can be still unhandled
},
[&]() // finally
{
// This code will be executed in all three cases:
// 1) exception was not thrown at all
// 2) exception was handled by one of the "catch" blocks above
// 3) exception was not handled by any of the "catch" block above
}
);
আপনি যদি চান তবে আপনি এই প্রতিমাটি "চেষ্টা - অবশেষে" ম্যাক্রোগুলিতে মুড়ে দিতে পারেন:
// Please never throw exception below. It is needed to avoid a compilation error
// in the case when we use "begin_try ... finally" without any "catch" block.
class never_thrown_exception {};
#define begin_try with_finally([&](){ try
#define finally catch(never_thrown_exception){throw;} },[&]()
#define end_try ) // sorry for "pascalish" style :(
এখন "শেষ অবধি" ব্লকটি সি ++ 11 এ উপলব্ধ:
begin_try
{
// A code that may throw
}
catch (const some_exception &)
{
// Handling some exceptions
}
finally
{
// A code that is always executed
}
end_try; // Sorry again for this ugly thing
ব্যক্তিগতভাবে আমি "অবশেষে" আইডিয়ামের "ম্যাক্রো" সংস্করণটি পছন্দ করি না এবং সেই ক্ষেত্রে একটি সিনট্যাক্স আরও বিশাল হলেও সেক্ষেত্রে খাঁটি "উইথ_ফিনালি" ফাংশনটি ব্যবহার করতে পছন্দ করি।
আপনি উপরের কোডটি এখানে পরীক্ষা করতে পারেন: http://coliru.stacked-crooked.com/a/1d88f64cb27b3813
পুনশ্চ
আপনার কোডটিতে শেষ অবধি যদি আপনার প্রয়োজন হয় তবে স্কোপড গার্ড বা ওএন_ফিনাল / ওএনএক্সসিএসপিএশন ম্যাক্রোগুলি সম্ভবত আপনার প্রয়োজনের সাথে আরও ভাল ফিট করে।
এখানে ব্যবহারের সংক্ষিপ্ত উদাহরণ ON_FINALLY / ON_EXCEPTION:
void function(std::vector<const char*> &vector)
{
int *arr1 = (int*)malloc(800*sizeof(int));
if (!arr1) { throw "cannot malloc arr1"; }
ON_FINALLY({ free(arr1); });
int *arr2 = (int*)malloc(900*sizeof(int));
if (!arr2) { throw "cannot malloc arr2"; }
ON_FINALLY({ free(arr2); });
vector.push_back("good");
ON_EXCEPTION({ vector.pop_back(); });
...
এই ধরণের পুরানো থ্রেডটি খননের জন্য দুঃখিত, তবে নিম্নলিখিত যুক্তিতে একটি বড় ত্রুটি রয়েছে:
RAII অবজেক্টের ব্যবহারকারী থেকে অবজেক্ট সুরক্ষার দায়িত্বটিকে অবজেক্টটির ডিজাইনার (এবং প্রয়োগকারী) এর দিকে নিয়ে যায়। আমি তর্ক করব এটি সঠিক জায়গা কারণ আপনার কেবলমাত্র ব্যতিক্রমী সুরক্ষা একবারে নেওয়া দরকার (নকশা / প্রয়োগের ক্ষেত্রে)। অবশেষে ব্যবহার করে আপনি প্রতিবার কোনও জিনিস ব্যবহার করার সময় ব্যতিক্রমী সুরক্ষাটি সঠিকভাবে নেওয়া দরকার correct
প্রায়শই না, আপনি গতিসম্পন্ন বরাদ্দ হওয়া অবজেক্টস, গতিশীল সংখ্যক অবজেক্টস ইত্যাদির সাথে মোকাবিলা করতে হবে ট্রাই-ব্লকের মধ্যে কিছু কোড অনেকগুলি অবজেক্ট তৈরি করতে পারে (রানটাইম সময়ে কতগুলি নির্ধারিত হয়) এবং তাদের তালিকায় একটি পয়েন্টার সঞ্চয় করে। এখন, এটি কোনও বহিরাগত দৃশ্য নয়, তবে খুব সাধারণ। এই ক্ষেত্রে, আপনি মত স্টাফ লিখতে চাই
void DoStuff(vector<string> input)
{
list<Foo*> myList;
try
{
for (int i = 0; i < input.size(); ++i)
{
Foo* tmp = new Foo(input[i]);
if (!tmp)
throw;
myList.push_back(tmp);
}
DoSomeStuff(myList);
}
finally
{
while (!myList.empty())
{
delete myList.back();
myList.pop_back();
}
}
}
অবশ্যই সুযোগের বাইরে যাওয়ার সময় তালিকাটি নিজেই ধ্বংস হয়ে যাবে, তবে এটি আপনার তৈরি অস্থায়ী বস্তুগুলি পরিষ্কার করবে না।
পরিবর্তে, আপনাকে কুৎসিত পথে যেতে হবে:
void DoStuff(vector<string> input)
{
list<Foo*> myList;
try
{
for (int i = 0; i < input.size(); ++i)
{
Foo* tmp = new Foo(input[i]);
if (!tmp)
throw;
myList.push_back(tmp);
}
DoSomeStuff(myList);
}
catch(...)
{
}
while (!myList.empty())
{
delete myList.back();
myList.pop_back();
}
}
এছাড়াও: কেন যে ম্যানেজ করা ল্যাঙ্গুয়েজগুলি যে কোনও উপায়ে আবর্জনা সংগ্রহকারী কর্তৃক স্বয়ংক্রিয়ভাবে স্বয়ংক্রিয়ভাবে অবনমিত হওয়া সত্ত্বেও অবশেষে ব্লক সরবরাহ করে?
ইঙ্গিত: কেবলমাত্র স্মৃতিশক্তি হ্রাসের চেয়ে "শেষ পর্যন্ত" আপনি আরও কিছু করতে পারেন।
new
নুল
std::shared_ptr
এবং std::unique_ptr
সরাসরি এবং stdlib এ অন্তর্ভুক্ত।
এফডব্লিউআইডাব্লু, মাইক্রোসফ্ট ভিজ্যুয়াল সি ++ চেষ্টা করে দেখার চেষ্টা করে, শেষ পর্যন্ত এবং এটি এমএফসি অ্যাপ্লিকেশনগুলিতে গুরুতর ব্যতিক্রমগুলি ধরার পদ্ধতি হিসাবে historতিহাসিকভাবে ব্যবহৃত হয়েছে যা অন্যথায় ক্রাশ হতে পারে। উদাহরণ স্বরূপ;
int CMyApp::Run()
{
__try
{
int i = CWinApp::Run();
m_Exitok = MAGIC_EXIT_NO;
return i;
}
__finally
{
if (m_Exitok != MAGIC_EXIT_NO)
FaultHandler();
}
}
আমি অতীতে এইগুলি প্রস্থান করার আগে খোলা ফাইলগুলির ব্যাকআপ সংরক্ষণের মতো কাজ করতে ব্যবহার করেছি। কিছু নির্দিষ্ট জেআইটি ডিবাগিং সেটিংস যদিও এই ব্যবস্থাকে ভেঙে দেবে।
অন্যান্য উত্তরে যেমন উল্লেখ করা হয়েছে, সি ++ finally
পছন্দসই কার্যকারিতা সমর্থন করে। সম্ভবত স্ট্যান্ডার্ড ভাষার অংশ হওয়ার সবচেয়ে কাছের এই কার্যকারিতাটির বাস্তবায়ন হ'ল সি ++ কোর গাইডলাইনস , ব্জন্ন স্টুস্ট্রপ এবং হার্ব সটার দ্বারা সম্পাদিত সি ++ ব্যবহারের জন্য সেরা অনুশীলনের একটি সেট। একটি বাস্তবায়নেরfinally
অংশ নির্দেশিকা সাপোর্ট লাইব্রেরী (GSL)। পুরো গাইডলাইনগুলি জুড়ে, finally
পুরানো শৈলীর ইন্টারফেসগুলির সাথে ডিল করার সময় এর ব্যবহারের পরামর্শ দেওয়া হয় এবং যদি কোনও উপযুক্ত সংস্থান হ্যান্ডেল না পাওয়া যায় তবে ক্লিনআপ প্রকাশ করার জন্য একটি চূড়ান্ত_অ্যাক্ট ব্যবহার করুন শিরোনাম রয়েছে ।
সুতরাং, কেবল সি ++ সমর্থন করে না finally
, এটি আসলে প্রচলিত সাধারণ ব্যবহারের ক্ষেত্রে এটি ব্যবহার করার পরামর্শ দেওয়া হয়।
জিএসএল বাস্তবায়নের উদাহরণ ব্যবহারের মতো হবে:
#include <gsl/gsl_util.h>
void example()
{
int handle = get_some_resource();
auto handle_clean = gsl::finally([&handle] { clean_that_resource(handle); });
// Do a lot of stuff, return early and throw exceptions.
// clean_that_resource will always get called.
}
জিএসএল বাস্তবায়ন এবং ব্যবহার পাওলো.বোলজোনির উত্তরের মতো একটির মতো । একটি পার্থক্য হ'ল কলটি gsl::finally()
অভাবের দ্বারা নির্মিত বস্তুর disable()
। আপনার যদি সেই কার্যকারিতাটির প্রয়োজন হয় (বলুন, একবার এটি সংস্থান করা হলে রিসোর্সটি ফিরিয়ে দিতে এবং কোনও ব্যতিক্রম ঘটতে বাধ্য নয়), আপনি পাওলোর বাস্তবায়ন পছন্দ করতে পারেন। অন্যথায়, জিএসএল ব্যবহার আপনার কাছে যেমন প্রমিত বৈশিষ্ট্যগুলি ব্যবহার করার তত কাছাকাছি।
আসলে নয়, তবে আপনি এগুলি কিছুটা প্রসারিত করতে পারেন, উদাহরণস্বরূপ:
int * array = new int[10000000];
try {
// Some code that can throw exceptions
// ...
throw std::exception();
// ...
} catch (...) {
// The finally-block (if an exception is thrown)
delete[] array;
// re-throw the exception.
throw;
}
// The finally-block (if no exception was thrown)
delete[] array;
মনে রাখবেন যে মূল ব্যতিক্রমটি পুনরায় নিক্ষেপ করার আগে অবশেষে-অবরুদ্ধটি নিজেই একটি ব্যতিক্রম ছুঁড়ে ফেলতে পারে, যার ফলে মূল ব্যতিক্রমটি ত্যাগ করে। এটি জাভা অবশেষে-ব্লকের মতো ঠিক একই আচরণ। এছাড়াও, আপনি return
চেষ্টা এবং ব্লক ধরার ভিতরে ব্যবহার করতে পারবেন না ।
std::exception_ptr e; try { /*try block*/ } catch (...) { e = std::current_exception(); } /*finally block*/ if (e) std::rethrow_exception(e);
finally
ব্লকের ভিতরে থেকে ব্যতিক্রম ছোঁড়ার অনুমতি দেওয়া উচিত ।
আমি নিয়ে এসেছেন finally
ম্যাক্রো ব্যবহার করা যেতে পারে যে প্রায় মত ¹ finally
জাভা শব্দ; এটি std::exception_ptr
এবং বন্ধুদের ব্যবহার করে , ল্যাম্বদা ফাংশন এবংstd::promise
, সুতরাং এটির প্রয়োজন হয় C++11
বা উপরে; এটি যৌগিক বিবৃতি এক্সপ্রেশন জিসিসি এক্সটেনশনটিও ব্যবহার করে, যা ঝনঝন দ্বারা সমর্থিত।
সতর্কতামূলক : এই উত্তরের পূর্ববর্তী সংস্করণটি আরও অনেক সীমাবদ্ধতার সাথে ধারণার একটি পৃথক বাস্তবায়ন ব্যবহার করেছে।
প্রথমে একটি সহায়ক শ্রেণীর সংজ্ঞা দেওয়া যাক।
#include <future>
template <typename Fun>
class FinallyHelper {
template <typename T> struct TypeWrapper {};
using Return = typename std::result_of<Fun()>::type;
public:
FinallyHelper(Fun body) {
try {
execute(TypeWrapper<Return>(), body);
}
catch(...) {
m_promise.set_exception(std::current_exception());
}
}
Return get() {
return m_promise.get_future().get();
}
private:
template <typename T>
void execute(T, Fun body) {
m_promise.set_value(body());
}
void execute(TypeWrapper<void>, Fun body) {
body();
}
std::promise<Return> m_promise;
};
template <typename Fun>
FinallyHelper<Fun> make_finally_helper(Fun body) {
return FinallyHelper<Fun>(body);
}
তারপরে আসল ম্যাক্রো আছে।
#define try_with_finally for(auto __finally_helper = make_finally_helper([&] { try
#define finally }); \
true; \
({return __finally_helper.get();})) \
/***/
এটি এর মতো ব্যবহার করা যেতে পারে:
void test() {
try_with_finally {
raise_exception();
}
catch(const my_exception1&) {
/*...*/
}
catch(const my_exception2&) {
/*...*/
}
finally {
clean_it_all_up();
}
}
এর ব্যবহার std::promise
এটি বাস্তবায়ন করা খুব সহজ করে তোলে তবে এটি সম্ভবত অপ্রয়োজনীয় ওভারহেডের একটি বিট প্রচলন করে যা কেবলমাত্র প্রয়োজনীয় ক্রিয়াকলাপগুলি পুনরায় প্রয়োগ করে এড়ানো যায় std::promise
।
¹ কভেট: এমন কয়েকটি জিনিস রয়েছে যা জাভা সংস্করণের মতো পুরোপুরি কাজ করে না finally
। আমার মাথার উপরে:
break
স্টেটমেন্টটির সাথে বাইরের লুপটি ভেদ করা সম্ভব নয়try
এবং catch()
এর ব্লকগুলির , যেহেতু তারা ল্যাম্বডা ফাংশনের মধ্যে থাকে;catch()
পরে ব্লকtry
: এটি একটি সি ++ প্রয়োজন;try
এবং catch()'s
ব্লকগুলির মধ্যে কোনও প্রত্যাবর্তন না ঘটে তবে সংকলন ব্যর্থ হবে কারণ finally
ম্যাক্রো কোডটিতে প্রসারিত হবে যা একটিটি ফিরে আসতে চাইবে void
। এই হতে পারে, পথ ভ্রষ্ট করবে, একটি অকার্যকরfinally_noreturn
ম্যাক্রোর প্রকারের দ্বারা এড ।সব মিলিয়ে আমি জানি না যে আমি এই জিনিসগুলি নিজেই ব্যবহার করতাম কিনা তবে এটির সাথে খেলে মজা পাওয়া গেল। :)
catch(xxx) {}
শুরুতে কেবল একটি অসম্ভব অবরুদ্ধ ব্লকটি রেখে কেভেট 2 থেকে মুক্তি পেতে পারেন finally
, যেখানে কমপক্ষে একটি ক্যাচ ব্লক থাকার উদ্দেশ্যে xxx একটি বোগাস প্রকার।
catch(...)
দেবে, তাই না?
xxx
একটি প্রাইভেট নেমস্পেসে কেবল একটি অস্পষ্ট ধরণ তৈরি করুন যা কখনই ব্যবহার করা হবে না।
আমার একটি ব্যবহারের কেস রয়েছে যেখানে আমি মনে করি যে এটি সি ++ 11 ভাষার একটি নিখুঁতভাবে গ্রহণযোগ্য অংশ finally
হওয়া উচিত , কারণ আমি মনে করি যে প্রবাহের দৃষ্টিকোণ থেকে এটি পড়া সহজ। আমার ব্যবহারের ক্ষেত্রটি থ্রেডের একটি ভোক্তা / প্রযোজক চেইন, যেখানে nullptr
সমস্ত থ্রেড বন্ধ করার জন্য রান শেষে প্রেরণেল প্রেরণ করা হয়।
যদি সি ++ এটি সমর্থন করে তবে আপনি চাইবেন যে আপনার কোডটি এমন দেখাচ্ছে:
extern Queue downstream, upstream;
int Example()
{
try
{
while(!ExitRequested())
{
X* x = upstream.pop();
if (!x) break;
x->doSomething();
downstream.push(x);
}
}
finally {
downstream.push(nullptr);
}
}
আমি মনে করি এটি আরও যুক্তিসঙ্গত যে লুপের শুরুতে আপনার শেষ অবধি ঘোষণা করা, যেহেতু লুপটি বেরিয়ে আসার পরে এটি ঘটে ... তবে এটি ইচ্ছাবাদী চিন্তাভাবনা কারণ আমরা এটি সি ++ এ করতে পারি না। নোট করুন যে সারিটি downstream
অন্য থ্রেডের সাথে সংযুক্ত রয়েছে, তাই আপনি এটির push(nullptr)
ডেস্ট্রাক্টরে সেন্ডিনেল downstream
রাখতে পারবেন না কারণ এটি এই মুহুর্তে ধ্বংস করা যায় না ... অন্য থ্রেডটি না পাওয়া পর্যন্ত এটি বেঁচে থাকা প্রয়োজনnullptr
।
সুতরাং এখানে ল্যাম্বদা সহ একটি আরআইআই ক্লাস কীভাবে ব্যবহার করবেন তা এখানে:
class Finally
{
public:
Finally(std::function<void(void)> callback) : callback_(callback)
{
}
~Finally()
{
callback_();
}
std::function<void(void)> callback_;
};
এবং আপনি এটি কীভাবে ব্যবহার করবেন তা এখানে:
extern Queue downstream, upstream;
int Example()
{
Finally atEnd([](){
downstream.push(nullptr);
});
while(!ExitRequested())
{
X* x = upstream.pop();
if (!x) break;
x->doSomething();
downstream.push(x);
}
}
অনেক লোক যেমন বলেছে, সমাধানটি হ'ল সি ++ 11 বৈশিষ্ট্যগুলি অবশেষে ব্লকগুলি এড়ানোর জন্য ব্যবহার করা। এর অন্যতম বৈশিষ্ট্য unique_ptr
।
এখানে RAII নিদর্শনগুলি ব্যবহার করে মেফেনের উত্তর লিখিত হয়েছে।
#include <vector>
#include <memory>
#include <list>
using namespace std;
class Foo
{
...
};
void DoStuff(vector<string> input)
{
list<unique_ptr<Foo> > myList;
for (int i = 0; i < input.size(); ++i)
{
myList.push_back(unique_ptr<Foo>(new Foo(input[i])));
}
DoSomeStuff(myList);
}
সি ++ স্ট্যান্ডার্ড লাইব্রেরি পাত্রে ব্যবহার করে ইউনিক_পিটার ব্যবহারের আরও কিছু ভূমিকা এখানে
আমি একটি বিকল্প প্রদান করতে চাই।
আপনি যদি অবশেষে অবরুদ্ধটিকে সর্বদা কল করার জন্য চান তবে এটি সর্বশেষ ক্যাচ ব্লকের পরে রাখুন (যা সম্ভবত catch( ... )
জানা ব্যতিক্রম না হওয়া উচিত )
try{
// something that might throw exception
} catch( ... ){
// what to do with uknown exception
}
//final code to be called always,
//don't forget that it might throw some exception too
doSomeCleanUp();
যদি আপনি অবশেষে অবশেষে ব্লক করতে চান তবে কোনও ব্যতিক্রম ছুঁড়ে ফেলা হলে আপনি বুলিয়ান স্থানীয় ভেরিয়েবল ব্যবহার করতে পারেন - রান করার আগে আপনি এটি মিথ্যাতে সেট করেন এবং ট্র্যাক ব্লকের একেবারে শেষে সত্য অ্যাসাইনমেন্ট রাখেন, তারপরে ভেরিয়েবলের জন্য ব্লক চেকের পরে মান:
bool generalAppState = false;
try{
// something that might throw exception
//the very end of try block:
generalAppState = true;
} catch( ... ){
// what to do with uknown exception
}
//final code to be called only when exception was thrown,
//don't forget that it might throw some exception too
if( !generalAppState ){
doSomeCleanUpOfDirtyEnd();
}
//final code to be called only when no exception is thrown
//don't forget that it might throw some exception too
else{
cleanEnd();
}
আমি আরও মনে করি যে ব্যতিক্রম পরিচালনা এবং শেষ পর্যন্ত থাকার জন্য আরআইআইএ কোনও সম্পূর্ণ কার্যকর প্রতিস্থাপন নয়। বিটিডাব্লু, আমিও মনে করি আরআইআইএ চারপাশে একটি খারাপ নাম। আমি এই ধরণের ক্লাসগুলিকে 'দরজা' বলি এবং তাদের প্রচুর ব্যবহার করি। 95% সময় তারা আরম্ভ করছে না বা সংস্থান অর্জন করছে না, তারা কোনও স্কোপড ভিত্তিতে কিছু পরিবর্তন প্রয়োগ করছে, বা ইতিমধ্যে সেট আপ করা হয়েছে এবং নিশ্চিত করেছে যে এটি ধ্বংস হয়ে গেছে। এটি আমার সরকারী প্যাটার্ন নাম হ'ল ইন্টারনেট আচ্ছন্ন হওয়া এমনকি আমার নামটি আরও ভাল হতে পারে বলে প্রস্তাব দেওয়ার জন্য আমি দুর্ব্যবহার করি।
আমি কেবল এটি যুক্তিসঙ্গত বলে মনে করি না যে প্রতিটি জটিল সেটআপ জিনিসগুলির কয়েকটি সেটআপের জন্য একটি ক্লাস লিখিত থাকতে হবে যাতে এটি রোধ করার সময় জটিলতাগুলি এড়ানোর জন্য সমস্ত কিছু ব্যাকআপের মুখোমুখি করার সময় এটির মুখোমুখি হতে হয় catch প্রক্রিয়াটিতে কিছু ভুল হলে ব্যতিক্রম প্রকারগুলি। এটি প্রচুর অ্যাডহক শ্রেণিতে নিয়ে যায় যা অন্যথায় প্রয়োজনীয় হবে না।
হ্যাঁ এটি একটি নির্দিষ্ট সংস্থান পরিচালনার জন্য ডিজাইন করা ক্লাসগুলির জন্য, বা অনুরূপ সংস্থানগুলির একটি সেট পরিচালনা করার জন্য ডিজাইন করা জেনেরিকগুলির পক্ষে এটি ঠিক। তবে, জড়িত সমস্ত কিছুর মধ্যে এমন মোড়ক থাকলেও, পরিষ্কারের সমন্বয়টি কেবল ধ্বংসকারীদের বিপরীতে আদেশের জন্য সহজ হতে পারে না।
আমি মনে করি সি ++ এর অবশেষে থাকার জন্য এটি সঠিক ধারণা দেয়। আমি বলতে চাই, জিজ, এতগুলি বিট এবং ববগুলি গত দশকগুলিতে এটির উপর আঠালো হয়ে গেছে যে মনে হচ্ছে যে অবাক লোকেরা হঠাৎ করে এমন কিছু বিষয়ে রক্ষণশীল হয়ে উঠবে যা বেশ কার্যকর হতে পারে এবং সম্ভবত কিছু অন্যান্য জিনিসের মতো জটিল কিছুই ছিল না যোগ করা হয়েছে (যদিও এটি আমার পক্ষ থেকে কেবল অনুমান))
try
{
...
goto finally;
}
catch(...)
{
...
goto finally;
}
finally:
{
...
}
finally
তা করে না।