ভার্চুয়াল ডেস্ট্রাক্টরগুলি ব্যবহার করার জন্য যদি আমি এটির প্রয়োজন নাও হয় তবে কী খরচ হবে?
কোনও শ্রেণীর সাথে কোনও ভার্চুয়াল ফাংশন প্রবর্তনের ব্যয় (উত্তরাধিকারসূত্রে বা শ্রেণীর সংজ্ঞাটির অংশ) সম্ভবত খুব খাড়া (বা বস্তুর উপর নির্ভর করে নয়) প্রতি বস্তুতে সঞ্চিত ভার্চুয়াল পয়েন্টারের প্রাথমিক ব্যয় যেমন:
struct Integer
{
virtual ~Integer() {}
int value;
};
এই ক্ষেত্রে, মেমরির ব্যয় তুলনামূলকভাবে প্রচুর। শ্রেণীর উদাহরণের আসল মেমরির আকারটি প্রায়শই 64৪-বিট আর্কিটেকচারে এ জাতীয় চেহারা দেখাবে:
struct Integer
{
// 8 byte vptr overhead
int value; // 4 bytes
// typically 4 more bytes of padding for alignment of vptr
};
এই Integer
শ্রেণীর জন্য মোট 16 বাইট মাত্র 4 বাইটের বিপরীতে। যদি আমরা এর মধ্যে মিলিয়ন সঞ্চয় করে রাখি তবে আমরা 16 মেগাবাইট মেমরির ব্যবহার সহ শেষ করব: সাধারণত 8 এমবি এল 3 সিপিইউ ক্যাশেটির দ্বিগুণ আকার এবং বারবার এ্যারেটি দিয়ে পুনরাবৃত্তি 4 মেগাবাইট সমমানের চেয়ে অনেকগুণ ধীর হতে পারে can অতিরিক্ত ক্যাশে মিস এবং পৃষ্ঠা ত্রুটির ফলে ভার্চুয়াল পয়েন্টার ছাড়াই।
এই বস্তুটির জন্য এই ভার্চুয়াল পয়েন্টারটির ব্যয়টি আরও ভার্চুয়াল ফাংশনগুলির সাথে বাড়বে না। আপনার একটি ক্লাসে 100 ভার্চুয়াল সদস্য ফাংশন থাকতে পারে এবং উদাহরণস্বরূপ ওভারহেড এখনও একক ভার্চুয়াল পয়েন্টার হতে পারে।
ভার্চুয়াল পয়েন্টার সাধারণত ওভারহেডের অবস্থান থেকে আরও তাত্ক্ষণিক উদ্বেগ। যাইহোক, উদাহরণস্বরূপ ভার্চুয়াল পয়েন্টার ছাড়াও প্রতি শ্রেণীর দাম। ভার্চুয়াল ফাংশন সহ প্রতিটি শ্রেণি একটি vtable
মেমোরিতে উত্পন্ন করে যা ভার্চুয়াল ফাংশন কল করার সময় প্রকৃতপক্ষে কল করা উচিত (ফাংশন / ডায়নামিক প্রেরণ) ফাংশনগুলির ঠিকানা সংরক্ষণ করে। vptr
তারপর এই শ্রেণীর-নির্দিষ্ট পয়েন্ট উদাহরণস্বরূপ প্রতি সঞ্চিত vtable
। এই ওভারহেডটি সাধারণত একটি কম উদ্বেগের বিষয়, তবে এটি আপনার বাইনারি আকারকে স্ফীত করে এবং কিছুটা রানটাইম ব্যয় যুক্ত করতে পারে যদি এই ওভারহেডটি কোনও জটিল কোডবেজে এক হাজার ক্লাসের জন্য অযথাই প্রদান করা হয়, উদাহরণস্বরূপ vtable
ব্যয়ের এই দিকটি আরও বেশি এবং আনুপাতিকভাবে বাড়িয়ে তোলে মিশ্রণে আরও ভার্চুয়াল ফাংশন।
পারফরম্যান্স-সমালোচনামূলক অঞ্চলে কাজ করা জাভা ডেভেলপাররা এই ধরণের ওভারহেডকে খুব ভালভাবে বুঝতে পারে (যদিও প্রায়শই বক্সিংয়ের প্রসঙ্গে বর্ণিত হয়), যেহেতু জাভা ব্যবহারকারী-সংজ্ঞায়িত টাইপটি কেন্দ্রীয় object
বেস শ্রেণীর থেকে স্পষ্টতই উত্তরাধিকার সূত্রে প্রাপ্ত এবং জাভাতে সমস্ত ফাংশন স্পষ্টত ভার্চুয়াল (ওভারিডেবল) ) অন্যথায় চিহ্নিত না হলে প্রকৃতিতে। ফলস্বরূপ, একটি জাভা Integer
একইভাবে vptr
উদাহরণস্বরূপ সম্পর্কিত স্টাইল মেটাডেটার ফলে 64-বিট প্ল্যাটফর্মে 16 বাইট মেমরির প্রবণতা অর্জন করতে পারে এবং int
রানটাইম প্রদান না করে জাভাতে সাধারণত একটি ক্লাসের মতো কোনও কিছু জড়িয়ে রাখা অসম্ভব impossible এটির জন্য পারফরম্যান্স ব্যয়।
তারপরে প্রশ্নটি হল: সি ++ কেন সমস্ত ডিস্ট্রাক্টরকে ডিফল্টরূপে ভার্চুয়াল সেট করে না?
সি ++ প্রকৃতপক্ষে "আপনি যেমন যান তেমন" মানসিকতার সাথে পারফরম্যান্সের পক্ষে এবং সি থেকে উত্তরাধিকার সূত্রে প্রাপ্ত অনেকগুলি খালি-ধাতু হার্ডওয়্যার-চালিত নকশাগুলি অযথা ভিটিবেল জেনারেশন এবং গতিশীল প্রেরণের জন্য প্রয়োজনীয় ওভারহেডকে অন্তর্ভুক্ত করতে চায় না জড়িত প্রতিটি একক শ্রেণী / উদাহরণ আপনি যদি সি ++ এর মতো ভাষা ব্যবহার করার মূল কারণগুলির মধ্যে একটি না হয়ে থাকেন তবে আপনি অন্যান্য প্রোগ্রামিং ভাষাগুলি থেকে আরও বেশি উপকৃত হতে পারেন কারণ C ++ ভাষা অনেকটা নিরাপদ এবং আদর্শের চেয়ে পারফরম্যান্সে থাকতে পারে তার চেয়ে বেশি কঠিন is মূলত যেমন একটি নকশা পক্ষে।
ভার্চুয়াল ডেস্ট্রাক্টরগুলি কখন ব্যবহার করার দরকার নেই?
বেশ প্রায়ই। যদি কোনও শ্রেণি উত্তরাধিকার সূত্রে ডিজাইন না করা হয়, তবে এর জন্য ভার্চুয়াল ডেস্ট্রাক্টর দরকার নেই এবং এটির প্রয়োজন নেই এমন কিছু জন্য কেবল একটি বৃহত ওভারহেড প্রদান করা শেষ হবে। একইভাবে, এমনকি যদি কোনও শ্রেণি উত্তরাধিকারসূত্রে ডিজাইন করা হয় তবে আপনি কখনই বেস পয়েন্টারের মাধ্যমে সাব টাইপ উদাহরণগুলি মুছবেন না, তবে এটির জন্য ভার্চুয়াল ডেস্ট্রাক্টরেরও প্রয়োজন নেই। সেক্ষেত্রে একটি নিরাপদ অনুশীলন হ'ল সুরক্ষিত অ ভার্চুয়াল ডেস্ট্রাক্টরকে সংজ্ঞায়িত করা,
class BaseClass
{
protected:
// Disallow deleting/destroying subclass objects through `BaseClass*`.
~BaseClass() {}
};
কোন ক্ষেত্রে আমার ভার্চুয়াল ডেস্ট্রাক্টর ব্যবহার করা উচিত নয়?
কখন ভার্চুয়াল ডেস্ট্রাক্টর ব্যবহার করা উচিত তা কভার করা সহজ actually বেশিরভাগ ক্ষেত্রে আপনার কোডবেসে আরও অনেক ক্লাস উত্তরাধিকারের জন্য ডিজাইন করা হবে না।
std::vector
উদাহরণস্বরূপ, উত্তরাধিকারসূত্রে ডিজাইন করা হয়নি এবং সাধারণত উত্তরাধিকার সূত্রে প্রাপ্ত হওয়া উচিত নয় (খুব নড়বড়ে নকশা), কারণ এটি পরে এই বেস পয়েন্টার মোছার ইস্যুতে প্রবণ হয়ে উঠবে ( std::vector
ইচ্ছাকৃতভাবে ভার্চুয়াল ডেস্ট্রাক্টরকে এড়িয়ে চলে) পাশাপাশি আনাড়ি বস্তু কাটা বিষয়গুলি যদি আপনার হয় উদ্ভূত শ্রেণি যে কোনও নতুন রাষ্ট্র যুক্ত করে।
সাধারণভাবে যে বর্গটি উত্তরাধিকার সূত্রে প্রাপ্ত তা হয় পাবলিক ভার্চুয়াল ডেস্ট্রাক্টর বা সুরক্ষিত, অ-ভার্চুয়াল থাকা উচিত। থেকে C++ Coding Standards
, অধ্যায় 50:
50. বেস ক্লাসের ডেস্ট্রাক্টরগুলিকে সর্বজনীন এবং ভার্চুয়াল, বা সুরক্ষিত এবং ভার্চুয়াল করুন। মুছতে, না মুছতে; এটিই প্রশ্ন: যদি বেস বেসে পয়েন্টারের মাধ্যমে মুছে ফেলার অনুমতি দেওয়া উচিত, তবে বেসের ডেস্ট্রাক্টর অবশ্যই সর্বজনীন এবং ভার্চুয়াল হতে হবে। অন্যথায়, এটি সুরক্ষিত এবং ভার্চুয়াল হওয়া উচিত।
সি ++ এর মধ্যে যে কোনও একটি বিষয় স্পষ্টভাবে জোর দেওয়ার দিকে ঝোঁক দেয় (কারণ ডিজাইনগুলি সত্যই ভঙ্গুর এবং বিশ্রী এবং সম্ভবত অন্যথায় অনিরাপদ হয়ে থাকে) এই ধারণাটি হ'ল উত্তরাধিকার উত্তরোত্তর হিসাবে ব্যবহার করার জন্য ডিজাইন করা কোনও প্রক্রিয়া নয়। এটি বহুবর্ষের কথা মাথায় রেখে একটি এক্সটেনসিবিলিটি মেকানিজম, তবে যেখানে এক্সটেনসিবিলিটি প্রয়োজন সে সম্পর্কে দূরদৃষ্টির প্রয়োজন। ফলস্বরূপ, আপনার বেস ক্লাসগুলি উত্তরাধিকারের ক্রমবর্ধমান সামনের অংশের গোড়া হিসাবে নকশাকৃত হওয়া উচিত, এবং এরপরে এমন কোনও দূরদৃষ্টি না করে আপনি পরবর্তীকালের উত্তরোত্তর হিসাবে উত্তরাধিকারী হন something
যেসব ক্ষেত্রে আপনি কেবল বিদ্যমান কোডটি পুনরায় ব্যবহার করার জন্য উত্তরাধিকারী হতে চান, সেখানে রচনাটি প্রায়শই দৃ strongly়ভাবে উত্সাহিত করা হয় (যৌগিক পুনরায় ব্যবহারের নীতিমালা)।