কোনও শ্রেণীর জন্য ভার্চুয়াল ডেস্ট্রাক্টর ঘোষণা না করার কোনও ভাল কারণ আছে কি ? আপনার কখন বিশেষভাবে একটি লেখা এড়ানো উচিত?
কোনও শ্রেণীর জন্য ভার্চুয়াল ডেস্ট্রাক্টর ঘোষণা না করার কোনও ভাল কারণ আছে কি ? আপনার কখন বিশেষভাবে একটি লেখা এড়ানো উচিত?
উত্তর:
নীচের যে কোনওটি সত্য হলে ভার্চুয়াল ডেস্ট্রাক্টর ব্যবহার করার দরকার নেই:
এড়াতে কোনও নির্দিষ্ট কারণ নেই যদি না আপনি স্মৃতিতে সত্যই চাপেন না।
প্রশ্নের সুস্পষ্ট উত্তর দিতে, অর্থাত্ কখন আপনি ভার্চুয়াল ডেস্ট্রাক্টর ঘোষণা করবেন না ।
সি ++ '98 / '03
ভার্চুয়াল ডেস্ট্রাক্টর যুক্ত করা আপনার ক্লাসকে পিওডি (সাধারণ পুরানো ডেটা) হতে বা * নন-পিওডিতে সামগ্রিকভাবে পরিবর্তন করতে পারে । এটি আপনার প্রকল্পের সংকলন থেকে থামিয়ে দিতে পারে যদি আপনার শ্রেণির ধরণের কোথাও একত্রিত হয়।
struct A {
// virtual ~A ();
int i;
int j;
};
void foo () {
A a = { 0, 1 }; // Will fail if virtual dtor declared
}
চূড়ান্ত ক্ষেত্রে, এই জাতীয় পরিবর্তনটি এমন একটি অপরিজ্ঞাত আচরণের কারণও হতে পারে যেখানে ক্লাসটি এমনভাবে ব্যবহৃত হয় যাতে কোনও পিওডের প্রয়োজন হয়, যেমন একটি উপবৃত্তাকার প্যারামিটারের মাধ্যমে এটি পাস করা, বা এটি মেমকিপি ব্যবহার করে।
void bar (...);
void foo (A & a) {
bar (a); // Undefined behavior if virtual dtor declared
}
[* একটি পিওডি টাইপ এমন এক ধরণের যা এর মেমরির বিন্যাস সম্পর্কে নির্দিষ্ট গ্যারান্টিযুক্ত থাকে। মানকটি সত্যিই কেবল বলেছে যে আপনি যদি পিওডি টাইপের সাথে কোনও জিনিস থেকে অক্ষরের অ্যারে (বা স্বাক্ষরবিহীন অক্ষর) এবং আবার ফিরে যান তবে ফলাফলটি আসল বস্তুর মতো হবে]]
আধুনিক সি ++
সি ++ এর সাম্প্রতিক সংস্করণগুলিতে, ক্লাস লেআউট এবং এর নির্মাণ, অনুলিপি এবং ধ্বংসের মধ্যে পিওডের ধারণাটি বিভক্ত হয়েছিল।
উপবৃত্তির ক্ষেত্রে, এটি আর অপরিজ্ঞাত আচরণ নয় এটি বর্তমানে শর্তসাপেক্ষে বাস্তবায়ন-সংজ্ঞায়িত শব্দার্থবিজ্ঞানের (N3937 - ~ C ++ '14 - 5.2.2 / 7) দ্বারা সমর্থিত:
... শ্রেণীর ধরণের একটি সম্ভাব্য-মূল্যায়িত যুক্তিটি পাস করা (ধারা 9) একটি তুচ্ছ-অনুলিপি অনুলিপি নির্মাণকারী, একটি তুচ্ছ ত্রিভুজকারী মুভ কনস্ট্রাক্টর, বা একটি ত্রি-ট্র্যাভিয়াল ডেস্ট্রাক্টর, যার সাথে কোনও প্যারামিটার নেই, শর্তসাপেক্ষে বাস্তবায়নের সাথে সমর্থনযোগ্য - সংজ্ঞায়িত শব্দার্থবিজ্ঞান।
অন্যটি ধ্বংসকারী ঘোষণা করার =default
অর্থ এটি তুচ্ছ নয় (12.4 / 5)
... একজন ডেস্ট্রাক্টর তুচ্ছ যদি এটি ব্যবহারকারীর দ্বারা সরবরাহ করা না হয় ...
আধুনিক সি ++ এ অন্য পরিবর্তনগুলি সামগ্রিক সূচনা সমস্যার প্রভাবকে কমিয়ে দেয় কারণ একজন নির্মাতা যুক্ত করা যেতে পারে:
struct A {
A(int i, int j);
virtual ~A ();
int i;
int j;
};
void foo () {
A a = { 0, 1 }; // OK
}
আমি যদি ভার্চুয়াল পদ্ধতিগুলি ব্যবহার করি তবেই আমি একটি ভার্চুয়াল ডেস্ট্রাক্টর ঘোষণা করি। আমার একবার ভার্চুয়াল পদ্ধতিগুলি হয়ে গেলে, আমি গাদাতে এটি ইনস্ট্যান্ট করা বা বেস ক্লাসে কোনও পয়েন্টার সংরক্ষণ করে এড়াতে নিজেকে বিশ্বাস করি না। এগুলি উভয়ই অত্যন্ত সাধারণ ক্রিয়াকলাপ এবং ধ্বংসকারীকে ভার্চুয়াল হিসাবে ঘোষণা না করা হলে প্রায়শই নিঃশব্দে সংস্থানগুলি সঞ্চার করবে।
ভার্চুয়াল ডেস্ট্রাক্টর প্রয়োজন হয় যখনই কোনও সুযোগ থাকে যা delete
আপনার শ্রেণীর ধরণের সহ একটি সাবক্লাসের কোনও অবজেক্টে পয়েন্টারে কল করা যেতে পারে। এটি নিশ্চিত করে যে সংকলক সময়ে গাদাতে কোনও অবজেক্টের ক্লাসটি জেনে কম্পাইলার ছাড়াই সঠিক ডেস্ট্রাক্টর রান সময়ে ডেকে আনে। উদাহরণস্বরূপ, ধরে নেওয়া B
হল এর একটি সাবক্লাস A
:
A *x = new B;
delete x; // ~B() called, even though x has type A*
যদি আপনার কোড পারফরম্যান্স সমালোচনা না করে তবে কেবল সুরক্ষার জন্য, আপনার লেখার প্রতিটি বেস ক্লাসে ভার্চুয়াল ডেস্ট্রাক্টর যুক্ত করা যুক্তিসঙ্গত হবে।
যাইহোক, আপনি যদি নিজেকে delete
টাইট লুপে প্রচুর পরিমাণে নিখরচায় খুঁজে পান তবে ভার্চুয়াল ফাংশন (এমনকি এটি খালিও) কল করার পারফরম্যান্সের ওভারহেডটি লক্ষণীয় হতে পারে। সংকলক সাধারণত এই কলগুলি ইনলাইন করতে পারে না এবং প্রসেসরের কোথায় যেতে হবে তা ভবিষ্যদ্বাণী করতে অসুবিধা হতে পারে। পারফরম্যান্সে এটির উল্লেখযোগ্য প্রভাব পড়ার সম্ভাবনা নেই তবে এটি উল্লেখ করার মতো।
ভার্চুয়াল ফাংশনগুলির অর্থ ভার্চুয়াল ফাংশন টেবিল পয়েন্টারটির সাহায্যে মেমরি ব্যয়ের প্রতিটি বরাদ্দকৃত বস্তু বৃদ্ধি পায়।
সুতরাং যদি আপনার প্রোগ্রামটিতে কিছু বড় সংখ্যক অবজেক্টের বরাদ্দ করা জড়িত থাকে তবে প্রতি বস্তুতে অতিরিক্ত 32 বিট সংরক্ষণ করার জন্য সমস্ত ভার্চুয়াল ফাংশন এড়ানো উচিত।
অন্যান্য সমস্ত ক্ষেত্রে, ডটর ভার্চুয়াল করতে আপনি নিজেকে ডিবাগ দুর্দশা বাঁচাতে পারবেন।
সমস্ত সি ++ ক্লাস গতিশীল পলিমারফিজম সহ বেস বর্গ হিসাবে ব্যবহারের জন্য উপযুক্ত নয়।
আপনি যদি চান যে আপনার শ্রেণিটি গতিশীল বহুবর্ষের জন্য উপযুক্ত হতে পারে তবে তার ডেস্ট্রাক্টরটি অবশ্যই ভার্চুয়াল হতে হবে। তদুপরি, একটি সাবক্লাস যে কোনও পদ্ধতি যা অনুমেয়ভাবে ওভাররাইড করতে চায় (যা অভ্যন্তরীণভাবে অভ্যন্তরীণভাবে ব্যবহৃত কিছু সুরক্ষিত এর অর্থ সমস্ত পাবলিক পদ্ধতির অর্থ হতে পারে) অবশ্যই ভার্চুয়াল হতে হবে।
যদি আপনার শ্রেণিটি গতিশীল বহুবর্ষের জন্য উপযুক্ত না হয়, তবে ধ্বংসকারীকে ভার্চুয়াল হিসাবে চিহ্নিত করা উচিত নয়, কারণ এটি করা বিভ্রান্তিকর। এটি লোককে আপনার ক্লাসটি ভুলভাবে ব্যবহার করতে উত্সাহ দেয়।
এখানে এমন একটি শ্রেণীর উদাহরণ রয়েছে যা গতিশীল পলিমার্ফিজমের পক্ষে উপযুক্ত নয়, এমনকি যদি এটির ডেস্ট্রাক্টর ভার্চুয়ালও ছিল:
class MutexLock {
mutex *mtx_;
public:
explicit MutexLock(mutex *mtx) : mtx_(mtx) { mtx_->lock(); }
~MutexLock() { mtx_->unlock(); }
private:
MutexLock(const MutexLock &rhs);
MutexLock &operator=(const MutexLock &rhs);
};
এই শ্রেণীর পুরো বিষয়টি হ'ল RAII এর জন্য স্ট্যাকের উপর বসে। যদি আপনি এই শ্রেণীর অবজেক্টের দিকে পয়েন্টারগুলি অতিক্রম করে থাকেন তবে এর সাবক্লাসটি একা ছেড়ে দিন, তবে আপনি এটি করছেন ভুল।
কোনও ডেস্ট্রাক্টরকে ভার্চুয়াল হিসাবে ঘোষণা না করার একটি ভাল কারণ হ'ল এটি যখন আপনার শ্রেণিকে ভার্চুয়াল ফাংশন সারণী যুক্ত করা থেকে বাঁচায় এবং যখনই সম্ভব আপনার এড়ানো উচিত।
আমি জানি যে অনেকে নিরাপদে পাশে থাকার জন্য সর্বদা ডেস্ট্রাক্টরগুলিকে ভার্চুয়াল হিসাবে ঘোষণা করতে পছন্দ করেন। তবে যদি আপনার ক্লাসে অন্য কোনও ভার্চুয়াল ফাংশন না থাকে তবে ভার্চুয়াল ডেস্ট্রাক্টর থাকার সত্যিকার অর্থেই সত্যই নেই। এমনকি আপনি যদি অন্য শ্রেণীর লোকদের থেকে ক্লাসটি দিয়ে থাকেন তবে সেগুলি থেকে অন্যান্য ক্লাস নেওয়া হয় তবে আপনার ক্লাসে উত্সাহিত পয়েন্টারটিতে তাদের কখনও ডিলিট কল করার কোনও কারণ নেই - এবং যদি তারা তা করে তবে আমি এটিকে ত্রুটি হিসাবে বিবেচনা করব।
ঠিক আছে, একটি একক ব্যতিক্রম আছে, যথা: যদি আপনার শ্রেণিটি (ভুলভাবে) উদ্ভূত অবজেক্টগুলির পলিমারফিক মুছে ফেলার জন্য ব্যবহৃত হয় তবে আপনি - বা অন্যান্য লোক - আশা করি জানেন যে এটির জন্য ভার্চুয়াল ডেস্ট্রাক্টর দরকার requires
অন্য একটি উপায় রাখুন, যদি আপনার শ্রেণিতে একটি অ-ভার্চুয়াল ডেস্ট্রাক্টর থাকে তবে এটি একটি খুব স্পষ্ট বক্তব্য: "উদ্ভূত অবজেক্টগুলি মুছতে আমাকে ব্যবহার করবেন না!"
আপনার যদি একটি বিশাল সংখ্যক উদাহরণ সহ খুব ছোট বর্গ থাকে তবে একটি ভেটেবল পয়েন্টারের ওভারহেড আপনার প্রোগ্রামের মেমরির ব্যবহারের ক্ষেত্রে পার্থক্য আনতে পারে। যতক্ষণ না আপনার ক্লাসে অন্য কোনও ভার্চুয়াল পদ্ধতি নেই, ডেস্ট্রাক্টরকে নন-ভার্চুয়াল তৈরি করা সেই ওভারহেডকে সাশ্রয় করবে।
আমি সাধারণত ডেস্ট্রাক্টর ভার্চুয়াল ঘোষণা করি, তবে আপনার যদি পারফরম্যান্স সমালোচনামূলক কোড থাকে যা একটি অভ্যন্তরীণ লুপে ব্যবহৃত হয়, আপনি ভার্চুয়াল টেবিল অনুসন্ধান এড়াতে চাইতে পারেন। এটি কয়েকটি ক্ষেত্রে যেমন সংঘর্ষের পরীক্ষার মতো গুরুত্বপূর্ণ হতে পারে। তবে যদি আপনি উত্তরাধিকার ব্যবহার করেন তবে কীভাবে আপনি এই জিনিসগুলি ধ্বংস করবেন সে সম্পর্কে সতর্কতা অবলম্বন করুন বা আপনি কেবলমাত্র অর্ধেকটি জিনিসটি ধ্বংস করবেন।
নোট করুন যে কোনও বস্তুর ভার্চুয়াল হলে কোনও বস্তুর জন্য ভার্চুয়াল টেবিল অনুসন্ধান হয় । সুতরাং আপনার যদি ক্লাসে অন্যান্য ভার্চুয়াল পদ্ধতি থাকে তবে কোনও ডেস্ট্রাক্টরের উপর ভার্চুয়াল স্পেসিফিকেশন সরিয়ে দেওয়ার কোনও মানে নেই।
যদি আপনার একেবারে ইতিবাচকভাবে অবশ্যই নিশ্চিত করতে হয় যে আপনার ক্লাসের কোনও ভিটিবেল না রয়েছে তবে আপনার অবশ্যই ভার্চুয়াল ডেস্ট্রাক্টরও রাখবেন না।
এটি বিরল ঘটনা, তবে তা ঘটে does
এটি করে এমন কোনও প্যাটার্নটির সর্বাধিক পরিচিত উদাহরণ হ'ল ডাইরেক্টএক্স ডি 3 ডিভিেক্টর এবং ডি 3 ডিএম্যাট্রিক্স ক্লাস। সিনট্যাকটিক চিনির জন্য ফাংশনগুলির পরিবর্তে এগুলি শ্রেণিবদ্ধ পদ্ধতি, তবে ক্রিয়াকলাপগুলি ওভারহেড এড়াতে ইচ্ছাকৃতভাবে ক্লাসগুলির একটি ভ্যাটবিল নেই কারণ এই ক্লাসগুলি অনেকগুলি উচ্চ-কর্মক্ষমতা অ্যাপ্লিকেশনগুলির অভ্যন্তরীণ লুপে বিশেষভাবে ব্যবহৃত হয়।
অপারেশন চলাকালীন যা বেস বর্গে সঞ্চালিত হবে, এবং এটি কার্যত আচরণ করা উচিত, ভার্চুয়াল হওয়া উচিত। যদি বেস ক্লাস ইন্টারফেসের মাধ্যমে মুছে ফেলা বহুরূপী সম্পাদন করা যায়, তবে এটি অবশ্যই কার্যত আচরণ করবে এবং ভার্চুয়াল হতে হবে।
আপনি শ্রেণি থেকে উদ্ভূত হওয়ার ইচ্ছা না রাখলে ডেস্ট্রাক্টরের ভার্চুয়াল হওয়ার দরকার নেই। এমনকি যদি আপনি এটি করেন তবে, বেস ক্লাস পয়েন্টারগুলি মুছার প্রয়োজন না হলে কোনও সুরক্ষিত অ-ভার্চুয়াল ডেস্ট্রাক্টর ঠিক তত ভাল ।
পারফরম্যান্সের উত্তরটি কেবলমাত্র আমিই জানি যার মধ্যে সত্য হওয়ার সম্ভাবনা রয়েছে। যদি আপনি পরিমাপ করে থাকেন এবং খুঁজে পেয়েছেন যে আপনার ডেস্ট্রাক্টরদের ডি-ভার্চুয়ালাইজিং করা সত্যিই জিনিসগুলিকে গতিময় করে তোলে, তবে আপনি সম্ভবত সেই শ্রেণীর অন্যান্য জিনিস পেয়েছেন যা দ্রুত বাড়ানো দরকার, তবে এই মুহূর্তে আরও গুরুত্বপূর্ণ বিবেচনা রয়েছে। কোনও দিন কেউ আবিষ্কার করতে যাচ্ছেন যে আপনার কোডটি তাদের জন্য একটি দুর্দান্ত বেস শ্রেণি সরবরাহ করবে এবং তাদের একটি সপ্তাহের কাজ সংরক্ষণ করবে। আপনার কোডটি বেস হিসাবে ব্যবহার না করে আপনার কোডটি অনুলিপি এবং আটকানো, তারা সেই সপ্তাহের কাজটি আরও ভাল করে নিশ্চিত করেছেন। আপনি আরও গুরুত্বপূর্ণ কিছু নিশ্চিত করে তুলতে চাইবেন যাতে আপনার কাছ থেকে কেউ উত্তরাধিকারী না হয়।