ভার্চুয়াল ডেস্ট্রাক্টর ব্যবহার করবেন না?


48

আমি বিশ্বাস করেছিলাম যে ভার্চুয়াল ডেস্ট্রাক্টর সম্পর্কে আমি অনেকবার অনুসন্ধান করেছি, বেশিরভাগ ভার্চুয়াল ডেস্ট্রাক্টরের উদ্দেশ্য এবং কেন আপনার ভার্চুয়াল ডেস্ট্রাক্টরগুলির প্রয়োজন mention এছাড়াও আমি মনে করি বেশিরভাগ ক্ষেত্রে ধ্বংসকারীদের ভার্চুয়াল হওয়া দরকার।

তারপরে প্রশ্নটি হল: সি ++ কেন সমস্ত ডিস্ট্রাক্টরকে ডিফল্টরূপে ভার্চুয়াল সেট করে না? বা অন্যান্য প্রশ্নে:

ভার্চুয়াল ডেস্ট্রাক্টরগুলি কখন ব্যবহার করার দরকার নেই?

কোন ক্ষেত্রে আমার ভার্চুয়াল ডেস্ট্রাক্টর ব্যবহার করা উচিত নয়?

ভার্চুয়াল ডেস্ট্রাক্টরগুলি ব্যবহার করার জন্য যদি আমি এটির প্রয়োজন নাও হয় তবে কী খরচ হবে?


6
এবং যদি আপনার ক্লাসটি উত্তরাধিকার সূত্রে প্রাপ্ত হওয়ার কথা না হয়? অনেক স্ট্যান্ডার্ড গ্রন্থাগার ক্লাস দেখুন, কিছু ভার্চুয়াল ফাংশন আছে কারণ তারা উত্তরাধিকার সূত্রে ডিজাইন করা হয়নি।
কিছু প্রোগ্রামার

4
এছাড়াও আমি মনে করি বেশিরভাগ ক্ষেত্রে ধ্বংসকারীদের ভার্চুয়াল হওয়া দরকার। নাঃ। একদমই না. যারা উত্তরাধিকারের অপব্যবহার করেন (রচনাকে সমর্থন করার চেয়ে) তারাও তাই মনে করে। আমি পুরো কয়েকটি অ্যাপ্লিকেশন কেবলমাত্র কয়েকটি মুখ্য ক্লাস এবং ভার্চুয়াল ফাংশন সহ দেখেছি।
ম্যাথিউ এম।

1
@ আসরকোর্ড_ডি সাধারণ বাস্তবায়নের সাথে সাথে যে কোনও বহুকর্মী শ্রেণীর জন্য অতিরিক্ত কোড উত্পন্ন হবে যদি না এই ধরণের সমস্ত অন্তর্নিহিত স্টাফটি ভ্রূচুয়াল এবং অপ্টিমাইজ করা না থাকে। সাধারণ এবিআই-এর মধ্যে এটিতে প্রতিটি শ্রেণির জন্য কমপক্ষে একটি ভিটেবিল জড়িত। ক্লাসের বিন্যাসও পরিবর্তন করতে হবে। আপনি কোনও পাবলিক ইন্টারফেসের অংশ হিসাবে এই ধরণের শ্রেণি প্রকাশ করার পরে আপনি নির্ভরযোগ্যভাবে ফিরে আসতে পারবেন না, কারণ এটি আবার পরিবর্তন করলে এবিআইয়ের সামঞ্জস্যতা নষ্ট হয়ে যায়, কারণ সাধারণভাবে ইন্টারফেসের চুক্তি হিসাবে ডেভারচুয়ালাইজেশন প্রত্যাশা করা সম্ভবত খারাপ (যদি সম্ভব হয়)।
ফ্র্যাঙ্কএইচবি

1
@ আসর_সো_ড "সংকলনের সময়" বাক্যাংশটি সঠিক নয়, তবে আমি মনে করি এর অর্থ একটি ভার্চুয়াল ডেস্ট্রাক্টর তুচ্ছ হতে পারে না বা নির্দিষ্ট কনস্টেক্সপ্রযুক্তও হতে পারে না, সুতরাং অতিরিক্ত কোড জেনারেশন এড়ানো কঠিন (যদি না আপনি সম্পূর্ণরূপে এই ধরণের বস্তুর ধ্বংস এড়াতে চান) সুতরাং এটি রানটাইম কর্মক্ষমতা কমবেশি ক্ষতি করে।
ফ্র্যাঙ্কএইচবি

2
"মাউন্ডসর_ডি" পয়েন্টারটি লাল হেরিং বলে মনে হচ্ছে। এটি সম্ভবত সদস্যের পয়েন্টার হওয়া উচিত (যা সংজ্ঞা অনুসারে কোনও পয়েন্টার নয় )। সাধারণ এবিআই'র সাথে মেম্বারের কাছে পয়েন্টারটি প্রায়শই একটি মেশিনের শব্দের সাথে খাপ খায় না (সাধারণত পয়েন্টার হিসাবে), এবং বহু-বহির্মুখী থেকে বহুবর্ষে কোনও শ্রেণি পরিবর্তন করা প্রায়শই এই শ্রেণীর সদস্যের পয়েন্টারের আকার পরিবর্তন করে।
ফ্র্যাঙ্কএইচবি

উত্তর:


41

যদি আপনি কোনও শ্রেণিতে ভার্চুয়াল ডেস্ট্রাক্টর যুক্ত করেন:

  • সর্বাধিক (সমস্ত?) বাস্তবায়ন সি ++ বাস্তবায়নের ক্ষেত্রে, শ্রেণীর প্রতিটি বস্তুর দৃষ্টান্তটি রানটাইম টাইপের জন্য ভার্চুয়াল প্রেরণ টেবিলের মধ্যে একটি পয়েন্টার সঞ্চয় করতে হবে, এবং সেই ভার্চুয়াল প্রেরণ টেবিলটি নিজেই এক্সিকিউটেবল ছবিতে যুক্ত হয়েছিল

  • ভার্চুয়াল প্রেরণ সারণীর ঠিকানা প্রসেসগুলি জুড়ে অগত্যা বৈধ নয়, যা ভাগ করে নেওয়া মেমরির মধ্যে নিরাপদে এই জাতীয় বিষয়গুলি ভাগ করে নেওয়া রোধ করতে পারে

  • এম্বেড করা ভার্চুয়াল পয়েন্টারটি কিছু পরিচিত ইনপুট বা আউটপুট ফর্ম্যাটের সাথে মিল রেখে মেমরি লেআউটের সাথে শ্রেণি তৈরি করতে হতাশ করে (উদাহরণস্বরূপ, একটি Price_Tick*সরাসরি ইনকামিং ইউডিপি প্যাকেটে উপযুক্তভাবে সাজানো মেমরির দিকে লক্ষ্য করা যেতে পারে এবং ডেটা পার্স / অ্যাক্সেস বা পরিবর্তন করতে ব্যবহৃত হয়, বা newবহির্গামী প্যাকেটে ডেটা লেখার জন্য এই জাতীয় শ্রেণীর স্থান নির্ধারণ )

  • ডেস্ট্রাক্টর তাদেরকে ফোন করতে পারে - নির্দিষ্ট শর্তে - কার্যত পাঠাতে হবে এবং তাই লাইন ছাড়িয়ে যেতে হবে, যেখানে অ-ভার্চুয়াল ডেস্ট্রাক্টর কলকারীর তুলনায় তুচ্ছ বা অপ্রাসঙ্গিক হতে পারে

উপরোক্ত বর্ণনার মতো ব্যবহারিক উপায়ে যদি আরও খারাপ না হয় তবে "আর্গুমেন্ট থেকে উত্তরাধিকারসূত্রে নকশাকৃত নকশাকৃত নকশাকৃত নকশাকৃত নকশাকৃত নকশাকৃত নকশাই যদি ব্যবহারিক কারণ না হয়; তবে প্রদত্ত হিসাবে এটি আরও খারাপ যে কখন ব্যয়টি পরিশোধ করা যায় তার একটি প্রধান মাপদণ্ড: আপনার শ্রেণিটি যদি বেস শ্রেণি হিসাবে ব্যবহার করা হয় তবে ভার্চুয়াল ডেস্ট্রাক্টর থাকার ক্ষেত্রে ডিফল্ট । এটি সর্বদা প্রয়োজনীয় নয়, তবে এটি নিশ্চিত করে যে উত্তরাধিকার সূত্রে ক্লাসগুলি দুর্ঘটনাজনিত সংজ্ঞায়িত আচরণ ছাড়াই আরও অবাধে ব্যবহার করা যেতে পারে যদি কোনও বর্গ শ্রেণীর বিন্যাসকারীকে যদি বেস ক্লাস পয়েন্টার বা রেফারেন্স ব্যবহার করে আহ্বান করা হয়।

"বেশিরভাগ ক্ষেত্রে ধ্বংসকারীদের ভার্চুয়াল হওয়া দরকার"

তাই না ... অনেক ক্লাসের এ জাতীয় কোনও প্রয়োজন নেই। এগুলির অনেকগুলি উদাহরণ রয়েছে যেখানে এগুলি অপ্রয়োজনীয় বলে মনে করা অযৌক্তিক বোধ করে তবে কেবল আপনার স্ট্যান্ডার্ড লাইব্রেরিটি দেখুন বা উত্সাহ দিন এবং আপনি দেখবেন যে ভার্চুয়াল ডেস্ট্রাক্টর নেই এমন অনেক শ্রেণীর ক্লাস রয়েছে। 1.53 এর বর্ধনে আমি 494 এর মধ্যে 72 ভার্চুয়াল ডেস্ট্রাক্টর গণনা করি।


23

কোন ক্ষেত্রে আমার ভার্চুয়াল ডেস্ট্রাক্টর ব্যবহার করা উচিত নয়?

  1. একটি কংক্রিট শ্রেণীর জন্য যা উত্তরাধিকারসূত্রে প্রাপ্ত হতে চায় না।
  2. পলিমারফিক মুছা ছাড়াই বেস ক্লাসের জন্য। হয় ক্লায়েন্টদের বেসে একটি পয়েন্টার ব্যবহার করে বহিরাগতভাবে মুছে ফেলা উচিত নয়।

BTW,

কোন ক্ষেত্রে ভার্চুয়াল ডেস্ট্রাক্টর ব্যবহার করা উচিত?

পলিমারফিক মুছে ফেলা সহ বেস ক্লাসের জন্য।


7
বিশেষত পলিমারফিক মুছে ফেলা ব্যতীত # 2 এর জন্য +1 । যদি আপনার ডেস্ট্রাক্টরটিকে কখনই বেস পয়েন্টারের মাধ্যমে প্রার্থনা করা না যায়, এটিকে ভার্চুয়াল তৈরি করা অপ্রয়োজনীয় এবং অপ্রয়োজনীয়, বিশেষত যদি আপনার ক্লাসের আগে ভার্চুয়াল ছিল না (তাই এটি আরটিটিআই দিয়ে নতুনভাবে ফুলে উঠেছে)। যে কোনও ব্যবহারকারীর এটি লঙ্ঘন করা থেকে রক্ষা করার জন্য, যেমন হার্ব সাটারের পরামর্শ অনুসারে, আপনি বেস ক্লাসের ডটরকে সুরক্ষিত এবং অ-ভার্চুয়াল বানিয়ে ফেলবেন, যাতে এটি কেবল কোনও উদ্ভূত ডেস্ট্রাক্টর দ্বারা / পরে প্রার্থনা করতে পারে।
আন্ডারস্কোর_ডি

@underscore_d এই প্রোগ্রামটিতে একটি গুরুত্বপূর্ণ পয়েন্ট যে আমি উত্তর মিস, শুধুমাত্র যদি আত যেখানে আমি একটি ভার্চুয়াল কন্সট্রাকটর প্রয়োজন উত্তরাধিকার উপস্থিতিতে যখন আমি নিশ্চিত যে এটা প্রয়োজন হয় না করতে পারেন যে
formerlyknownas_463035818

14

ভার্চুয়াল ডেস্ট্রাক্টরগুলি ব্যবহার করার জন্য যদি আমি এটির প্রয়োজন নাও হয় তবে কী খরচ হবে?

কোনও শ্রেণীর সাথে কোনও ভার্চুয়াল ফাংশন প্রবর্তনের ব্যয় (উত্তরাধিকারসূত্রে বা শ্রেণীর সংজ্ঞাটির অংশ) সম্ভবত খুব খাড়া (বা বস্তুর উপর নির্ভর করে নয়) প্রতি বস্তুতে সঞ্চিত ভার্চুয়াল পয়েন্টারের প্রাথমিক ব্যয় যেমন:

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়ভাবে উত্সাহিত করা হয় (যৌগিক পুনরায় ব্যবহারের নীতিমালা)।


9

সি ++ কেন ডিফল্টভাবে সমস্ত ডেস্ট্রাক্টর ভার্চুয়াল সেট করে না? অতিরিক্ত স্টোরেজ এবং ভার্চুয়াল পদ্ধতি সারণীর কল Cost সি ++ সিস্টেম, লো-লেটেন্সি, আরটি প্রোগ্রামিংয়ের জন্য ব্যবহৃত হয় যেখানে এটি বোঝা হতে পারে।


শক্ত রিয়েল টাইম সিস্টেমে ডেস্ট্রাক্টরদের প্রথম স্থানে ব্যবহার করা উচিত নয় কারণ গতিশীল মেমরির মতো অনেক সংস্থান শক্তিশালী সময়সীমা গ্যারান্টি সরবরাহের জন্য ব্যবহার করা যায় না
মার্কো এ

9
@MarcoA। যেহেতু ডেস্ট্রাক্টররা গতিশীল মেমরি বরাদ্দ বোঝায়?
chbaker0

@ chbaker0 আমি একটি 'পছন্দ' ব্যবহার করেছি। এগুলি কেবল আমার অভিজ্ঞতায় ব্যবহার হয় না।
মার্কো এ

6
এটি আজেবাজে কথা যে গতিশীল মেমরি হার্ড রিয়েল-টাইম সিস্টেমে ব্যবহার করা যায় না। এটি নির্ধারণ করা মোটামুটি তুচ্ছ যে স্থির বরাদ্দ মাপের একটি পূর্ব-কনফিগার্ড গাদা এবং একটি বরাদ্দ বিটম্যাপ হয় মেমরি বরাদ্দ করে দেয় বা সেই বিটম্যাপটি স্ক্যান করতে সময় নেওয়ার পরে স্মৃতি ছাড়িয়ে যায়।
MSalters

@ মাল্টারগুলি যা আমাকে ভাবিয়ে তোলে: এমন একটি প্রোগ্রামের কল্পনা করুন যেখানে প্রতিটি অপারেশনের ব্যয় টাইপ সিস্টেমে রাখা হয়েছিল। রিয়েলটাইম গ্যারান্টিগুলির সংকলন-সময় চেকের অনুমতি দেওয়া।
ইয়াক্ক

5

ভার্চুয়াল ডেস্ট্রাক্টর কখন ব্যবহার করবেন না এটির একটি উত্তম উদাহরণ: স্কট মায়ার্স থেকে:

যদি কোনও শ্রেণিতে কোনও ভার্চুয়াল ফাংশন না থাকে, তবে এটি প্রায়শই ইঙ্গিত দেয় যে এটি বেস ক্লাস হিসাবে ব্যবহার করা নয়। যখন কোনও শ্রেণি বেস ক্লাস হিসাবে ব্যবহার করার উদ্দেশ্যে নয়, তখন ডেস্ট্রাক্টর ভার্চুয়াল তৈরি করা সাধারণত একটি খারাপ ধারণা। এআরএমের আলোচনার ভিত্তিতে এই উদাহরণটি বিবেচনা করুন:

// class for representing 2D points
class Point {
public:
    Point(short int xCoord, short int yCoord);
    ~Point();
private:
    short int x, y;
};

যদি একটি শর্ট ইনট 16 বিট দখল করে তবে একটি পয়েন্ট অবজেক্ট 32-বিট রেজিস্টারে ফিট করতে পারে। তদ্ব্যতীত, পয়েন্ট অবজেক্টটি 32-বিট পরিমাণ হিসাবে অন্যান্য ভাষায় যেমন সি বা ফোরট্রানগুলিতে লিখিত ফাংশনগুলিতে প্রেরণ করা যায়। যদি পয়েন্টের ডেস্ট্রাক্টরটিকে ভার্চুয়াল করা হয় তবে পরিস্থিতি পরিবর্তন হয়।

আপনি ভার্চুয়াল সদস্য যুক্ত করার মুহুর্তে, আপনার শ্রেণিতে একটি ভার্চুয়াল পয়েন্টার যুক্ত হবে যা সেই শ্রেণীর জন্য ভার্চুয়াল টেবিলকে নির্দেশ করবে।


If a class does not contain any virtual functions, that is often an indication that it is not meant to be used as a base class.Wut। গুড ওল্ড ডে'র কথা কি অন্য কেউ মনে করে, যেখানে ভার্চুয়াল পদ্ধতিগুলির কোনও যত্ন না নিয়েই পুনরায় ব্যবহারযোগ্য সদস্য এবং আচরণের ধারাবাহিক স্তরগুলি তৈরি করার জন্য আমাদের ক্লাস এবং উত্তরাধিকার ব্যবহারের অনুমতি দেওয়া হয়েছিল? ক্যামন, স্কট আমি মূল পয়েন্টটি পাই তবে এটি "প্রায়শই" সত্যিই পৌঁছায়।
আন্ডারস্কোর_

3

ভার্চুয়াল ডেস্ট্রাক্টর একটি রানটাইম ব্যয় যোগ করে। ক্লাসে অন্য কোনও ভার্চুয়াল পদ্ধতি না থাকলে ব্যয়টি বিশেষত দুর্দান্ত। ভার্চুয়াল ডেস্ট্রাক্টর শুধুমাত্র একটি নির্দিষ্ট দৃশ্যে প্রয়োজন, যেখানে কোনও অবজেক্ট মুছে ফেলা হয় বা অন্যথায় কোনও বেস শ্রেণীর পয়েন্টারের মাধ্যমে ধ্বংস করা হয়। এই ক্ষেত্রে, বেস শ্রেণীর ডেস্ট্রাক্টর অবশ্যই ভার্চুয়াল হতে হবে এবং যে কোনও উদ্ভূত শ্রেণীর ডেস্ট্রাক্টর স্পষ্টভাবে ভার্চুয়াল হতে পারে। কয়েকটি পরিস্থিতি রয়েছে যেখানে পলিমারফিক বেস শ্রেণিটি এমনভাবে ব্যবহার করা হয় যাতে ধ্বংসকারীকে ভার্চুয়াল হওয়ার প্রয়োজন হয় না:

  • যদি উত্সযুক্ত শ্রেণীর উদাহরণগুলি হিপগুলিতে বরাদ্দ না করা হয়, উদাহরণস্বরূপ কেবল স্ট্যাকের উপর বা অন্যান্য বস্তুর ভিতরে। (আপনি যদি অবিশ্রান্ত মেমরি এবং প্লেসমেন্ট অপারেটরটি নতুন ব্যবহার করেন তবে ব্যতীত))
  • যদি উত্সযুক্ত শ্রেণীর উদাহরণগুলি হিপগুলিতে বরাদ্দ করা হয় তবে মুছে ফেলা কেবলমাত্র সবচেয়ে উত্সযুক্ত শ্রেণীর পয়েন্টারগুলির মাধ্যমে ঘটে থাকে, যেমন একটি রয়েছে std::unique_ptr<Derived>এবং পলিমারফিজমটি কেবল অ-মালিকানাধীন পয়েন্টার এবং রেফারেন্সের মাধ্যমে ঘটে। আর একটি উদাহরণ হ'ল যখন বস্তুগুলি ব্যবহার করে বরাদ্দ দেওয়া হয় std::make_shared<Derived>()std::shared_ptr<Base>প্রাথমিক পয়েন্টারটি যেমন ছিল ততক্ষণ ব্যবহার করা ঠিক std::shared_ptr<Derived>। এটি কারণ ভাগ করা পয়েন্টারগুলির ডেস্ট্রাক্টরদের (মুছে ফেলার) জন্য তাদের নিজস্ব গতিশীল প্রেরণ রয়েছে যা অগত্যা ভার্চুয়াল বেস শ্রেণীর ডেস্ট্রাক্টরের উপর নির্ভর করে না।

অবশ্যই, কেবলমাত্র উপরে বর্ণিত উপায়ে ব্যবহার করার জন্য যে কোনও সম্মেলন সহজেই ভাঙ্গা যায়। সুতরাং, ভেষজ সুতারের পরামর্শ আগের মতোই বৈধ রয়েছে: "বেস শ্রেণীর ধ্বংসকারীরা হয় পাবলিক এবং ভার্চুয়াল, বা সুরক্ষিত এবং অ-ভার্চুয়াল হওয়া উচিত" " এইভাবে, যদি কেউ অ-ভার্চুয়াল ডেস্ট্রাক্টর (গুলি) সহ বেস ক্লাসে কোনও পয়েন্টার মোছার চেষ্টা করে তবে সে সম্ভবত সংকলনের সময় অ্যাক্সেস লঙ্ঘনের ত্রুটিটি গ্রহণ করবে।

তারপরে আবার এমন কিছু ক্লাস রয়েছে যা (পাবলিক) বেস ক্লাস হিসাবে নকশাকৃত নয়। আমার ব্যক্তিগত সুপারিশ হ'ল এগুলিকে finalসি ++ 11 বা উচ্চতর করা। যদি এটি একটি বর্গক্ষেত্রের পেগ হিসাবে ডিজাইন করা থাকে তবে সম্ভাবনা রয়েছে যে এটি একটি গোল প্যাগ হিসাবে খুব ভাল কাজ করবে না। বেস ক্লাস এবং ডেরিভড ক্লাসের মধ্যে সুস্পষ্ট উত্তরাধিকার চুক্তি, এনভিআই (নন-ভার্চুয়াল ইন্টারফেস) ডিজাইন প্যাটার্নের জন্য, কংক্রিট বেস ক্লাসের চেয়ে বিমূর্তের জন্য এবং সুরক্ষিত সদস্য ভেরিয়েবলগুলির আমার ঘৃণা, অন্যান্য বিষয়গুলির সাথে এটি আমার পছন্দের সাথে সম্পর্কিত , তবে আমি জানি এই সমস্ত দৃষ্টিভঙ্গি কিছুটা বিতর্কিত।


1

virtualযখন আপনি নিজের classউত্তরাধিকার সূত্রে পরিকল্পনা করার পরিকল্পনা করেন তখনই একজন ডেস্ট্রাক্টর ঘোষণা করা প্রয়োজনীয় । সাধারণত স্ট্যান্ডার্ড লাইব্রেরির ক্লাসগুলি (যেমন std::string) কোনও ভার্চুয়াল ডেস্ট্রাক্টর সরবরাহ করে না এবং এটি সাবক্লাসিংয়ের জন্য নয়।


3
কারণটি পলিমারফিজমের সাবক্লাসিং + ব্যবহার। একটি গতিশীল রেজোলিউশন প্রয়োজন হলেই ভার্চুয়াল ডেস্ট্রাক্টর প্রয়োজন, এটি একটি রেফারেন্স / পয়েন্টার / মাস্টার ক্লাসে যা কিছু হোক প্রকৃতপক্ষে একটি সাবক্লাসের উদাহরণকে উল্লেখ করতে পারে।
মিশেল বিলাউড

2
@ মিশেলবিলাউড আসলে আপনি এখনও ভার্চুয়াল ডেক্টর ছাড়াই বহুত্ববাদ করতে পারেন। পলিমারফিক মুছার জন্য ভার্চুয়াল ডটর কেবলমাত্র প্রয়োজনীয়, অর্থাত্ deleteএকটি বেস ক্লাসে পয়েন্টারে কল করা।
chbaker0

1

ভিটিবেল তৈরির জন্য কনস্ট্রাক্টরটিতে একটি ওভারহেড থাকবে (যদি আপনার অন্যান্য ভার্চুয়াল ফাংশন না থাকে তবে আপনি সম্ভবত, তবে সবসময় না, ভার্চুয়াল ডেস্ট্রাক্টরও থাকা উচিত)। এবং যদি আপনার অন্য কোনও ভার্চুয়াল ফাংশন না থাকে তবে এটি আপনার অবজেক্টটিকে অন্যথায় প্রয়োজনীয়তার চেয়ে এক পয়েন্টার-আকারের আকারে বড় করে তোলে। স্পষ্টতই, বর্ধিত আকারের ছোট বস্তুগুলিতে একটি বড় প্রভাব ফেলতে পারে।

ভিটিবেল পেতে একটি অতিরিক্ত মেমরি পড়ে আছে এবং তারপরে ফাংশনটিকে পরোক্ষভাবে কল করতে পারে, যা ডাস্ট্রাক্টর ডেকে আনা হলে ভার্চুয়াল ডেস্ট্রাক্টরের ওভারহেড হয়। এবং অবশ্যই, ফলস্বরূপ, ডেস্ট্রাক্টরের প্রতিটি কলের জন্য একটি সামান্য অতিরিক্ত কোড উত্পন্ন। এটি এমন কেসগুলির ক্ষেত্রে যেখানে সংকলক প্রকৃত প্রকারটি অনুমিত করতে পারে না - যেসব ক্ষেত্রে এটি প্রকৃত প্রকারটি ছাড়িয়ে নিতে পারে, সংকলকটি ভিটিবেল ব্যবহার করবে না, তবে সরাসরি ডেস্ট্রাক্টরকে কল করবে।

আপনি উচিত যদি আপনার বর্গ বিশেষত, একটি বেস-শ্রেণী হিসেবে দেয়ার উদ্দেশ্যে করা হচ্ছে তা / তৈরি করা যেতে পারে কোড জানে যে এটা কি ধরনের সৃষ্টি এ, তাহলে আপনি একটি ভার্চুয়াল বিনাশকারী প্রয়োজন চেয়ে অন্য কিছু সত্তা দ্বারা ধ্বংস একটি ভার্চুয়াল বিনাশকারী আছে।

আপনি যদি নিশ্চিত না হন তবে ভার্চুয়াল ডেস্ট্রাক্টর ব্যবহার করুন। "ডান ডিস্ট্রাক্টর বলা হয় না" এর ফলে তৈরি বাগটি খুঁজে পাওয়ার চেষ্টা করার চেয়ে ভার্চুয়ালটিকে মুছে ফেলা সহজ।

সংক্ষেপে বলতে গেলে আপনি করা উচিত নয় 1. আপনি কোন ভার্চুয়াল ফাংশন নেই: একটি ভার্চুয়াল বিনাশকারী যদি আছে। 2. ক্লাস থেকে উদ্ভূত হবে finalনা (এটি সি ++ 11 তে চিহ্নিত করুন, আপনি এটি থেকে উদ্ভূত হওয়ার চেষ্টা করলে সংকলকটি সেভাবে জানাবে)।

বেশিরভাগ ক্ষেত্রে, "প্রচুর পরিমাণে সামগ্রী" না থাকলে নির্দিষ্ট বস্তু ব্যবহার করে ব্যয় করা সময়ের একটি বড় অংশটি সৃষ্টি এবং ধ্বংস হয় না (1 এমবি স্ট্রিং তৈরি করতে অবশ্যই কিছুটা সময় লাগে, কারণ কমপক্ষে 1MB ডেটা প্রয়োজন এটি বর্তমানে যেখানেই রয়েছে সেখান থেকে অনুলিপি করুন)। 1 এমবি স্ট্রিং তৈরি করা 150b স্ট্রিংয়ের ধ্বংসের চেয়ে খারাপ নয়, উভয়ই স্ট্রিং স্টোরেজকে হ্রাস করতে হবে এবং অন্য কিছু নয়, সুতরাং সেখানে সময় কাটানো সাধারণত একই থাকে [যদি না এটি একটি ডিবাগ বিল্ড হয়, যেখানে ডিএলোকেশন প্রায়শই স্মৃতি পূরণ করে "বিষ প্যাটার্ন" - তবে এটি আপনি প্রযোজনায় আসল প্রয়োগ চালাতে যাবেন না]।

সংক্ষেপে, একটি ছোট ওভারহেড রয়েছে তবে ছোট বস্তুর জন্য এটি একটি পার্থক্য করতে পারে।

আরও নোট করুন যে সংকলকরা কিছু ক্ষেত্রে ভার্চুয়াল লুকআপকে অপ্টিমাইজ করতে পারে, সুতরাং এটি কেবল একটি জরিমানা

সর্বদা হিসাবে যখন এটি কর্মক্ষমতা, মেমরির পদচিহ্ন এবং এর মতো হয়: বেঞ্চমার্ক এবং প্রোফাইল এবং পরিমাপ, বিকল্পগুলির সাথে ফলাফলগুলি তুলনা করুন এবং সর্বাধিক সময় / স্মৃতি কোথায় ব্যয় হয়েছে তা দেখুন, এবং 90% অপ্টিমাইজ করার চেষ্টা করবেন না কোড যা খুব বেশি চালিত হয় না [বেশিরভাগ অ্যাপ্লিকেশনগুলিতে প্রায় 10% কোড থাকে যা কার্যকরকরণের সময় অত্যন্ত প্রভাবশালী এবং 90% কোডের তেমন প্রভাব থাকে না]। এটি একটি উচ্চতর অপ্টিমাইজেশান স্তরে করুন, যাতে আপনার ইতিমধ্যে একটি ভাল কাজ করে সংকলকটির সুবিধা রয়েছে! এবং পুনরাবৃত্তি করুন, আবার চেক করুন এবং ধাপের দিকের উন্নতি করুন। চালাক হওয়ার চেষ্টা করবেন না এবং সেই নির্দিষ্ট অ্যাপ্লিকেশনটির সাথে আপনার প্রচুর অভিজ্ঞতা না থাকলে কোনটি গুরুত্বপূর্ণ এবং কী নয় তা নির্ধারণের চেষ্টা করবেন না।


1
"ভেটেবল তৈরির জন্য কনস্ট্রাক্টরের একটি ওভারহেড হবে" - ভেটেবল সাধারণত কমপায়ার দ্বারা প্রতি শ্রেণির ভিত্তিতে "তৈরি" হয়, কনস্ট্রাক্টর কেবল নির্মাণাধীন অবজেক্টে এটিতে পয়েন্টার সংরক্ষণের ওভারহেড রাখে।
টনি

এছাড়াও ... আমি অকালীন অপ্টিমাইজেশান এড়িয়ে চলেছি, তবে বিপরীতভাবে You **should** have a virtual destructor if your class is intended as a base-classএটি একটি স্থূল ওভারসিম্প্লিফিকেশন - এবং অকাল হতাশাবোধ । এটি কেবল তখনই প্রয়োজন যখন কাউকে পয়েন্টার থেকে বেস পর্যন্ত কোনও উত্পন্ন ক্লাস মুছতে দেওয়া হয়। অনেক পরিস্থিতিতে তা হয় না। যদি আপনি এটি জানেন তবে নিশ্চিত, ওভারহেড ব্যয় করুন। সংকলক দ্বারা প্রকৃত কলগুলি স্থিতিশীলভাবে সমাধান করা গেলেও , বিটিডব্লিউ, সর্বদা যুক্ত করা হয়। অন্যথায়, আপনি যখন লোকেরা আপনার জিনিসগুলির সাথে কী করতে পারেন তা আপনি যখন সঠিকভাবে নিয়ন্ত্রণ করেন তখন তা সার্থক হয় না
আন্ডারস্কোর_ড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.