খালি বেস ক্লাসটিও যদি সদস্যের পরিবর্তনশীল হয় তবে খালি বেস অপ্টিমাইজেশন কেন নিষিদ্ধ?


14

খালি বেস অপ্টিমাইজেশন দুর্দান্ত। তবে এটি নিম্নলিখিত বিধিনিষেধের সাথে আসে:

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

এই সীমাবদ্ধতার ব্যাখ্যা দিতে, নিম্নলিখিত কোডটি বিবেচনা করুন। static_assertব্যর্থ হবে। তবে, পরিবর্তিত হয়ে Fooবা Barপরিবর্তে উত্তরাধিকার সূত্রে Base2পরিবর্তন করলে ত্রুটিটি এড়ানো যাবে:

#include <cstddef>

struct Base  {};
struct Base2 {};

struct Foo : Base {};

struct Bar : Base {
    Foo foo;
};

static_assert(offsetof(Bar,foo)==0,"Error!");

আমি এই আচরণটি পুরোপুরি বুঝতে পারি। আমি যা বুঝতে পারি না তা হ'ল এই বিশেষ আচরণটি কেন বিদ্যমান । এটি স্পষ্টতই একটি কারণে যুক্ত করা হয়েছে, কারণ এটি একটি সুস্পষ্ট সংযোজন, তদারকি নয়। এর পক্ষে যুক্তি কী?

বিশেষত, দুটি বেস সাবোবজেক্টের আলাদা ঠিকানা থাকতে হবে কেন? উপরের দিকে, Barএকটি প্রকার এবং fooসেই ধরণের একটি সদস্য ভেরিয়েবল। আমি দেখতে পাচ্ছি না কেন বেসের বর্গটি Barধরণের ধরণের fooবা বিপরীত দিকের বেস শ্রেণীর সাথে সম্পর্কিত ।

প্রকৃতপক্ষে, আমি যদি কিছু বলি তবে আমি এটির &fooসাথে থাকা Barউদাহরণের ঠিকানার মতোই আশা করব other যেমনটি অন্যান্য পরিস্থিতিতে হওয়া প্রয়োজন (1) । সর্বোপরি, আমি virtualউত্তরাধিকার নিয়ে অভিনব কিছু করছি না , বেস ক্লাস নির্বিশেষে খালি, এবং সংকলন Base2দেখায় যে এই বিশেষ ক্ষেত্রে কিছুই ভাঙ্গেনি।

তবে স্পষ্টতই এই যুক্তিটি কোনওভাবে ভুল, এবং এমন অন্যান্য পরিস্থিতি রয়েছে যেখানে এই সীমাবদ্ধতার প্রয়োজন হবে।

আসুন বলি যে উত্তরগুলি C ++ 11 বা আরও নতুন (আমি বর্তমানে সি ++ 17 ব্যবহার করছি) এর জন্য হওয়া উচিত।

(1) দ্রষ্টব্য: EBO সি ++ 11 এ আপগ্রেড হয়েছে এবং বিশেষত এসগুলির জন্য বাধ্যতামূলক হয়ে উঠেছে StandardLayoutType(যদিও Barউপরে, এটি একটি নয় StandardLayoutType)।


4
আপনি যে যুক্তিটি উদ্ধৃত করেছেন (" যেহেতু একই ধরণের দুটি বেস সাবোবজেক্টগুলির পৃথক ঠিকানা থাকা প্রয়োজন ") কীভাবে সংক্ষিপ্ত হবে? একই ধরণের বিভিন্ন বস্তুর পৃথক ঠিকানা থাকতে হবে এবং এই প্রয়োজনীয়তাটি নিশ্চিত করে যে আমরা সেই নিয়মটি ভঙ্গ করব না। যদি খালি বেস অপ্টিমাইজেশানটি এখানে প্রয়োগ করা Base *a = new Bar(); Base *b = a->foo;হয় a==bতবে আমাদের সাথে থাকতে পারে , তবে aএবং bস্পষ্টতই পৃথক অবজেক্ট (সম্ভবত বিভিন্ন ভার্চুয়াল পদ্ধতিতে ওভাররাইড সহ)।
টবি স্পিড

1
ভাষা-উকিলের উত্তরটি অনুমানের সম্পর্কিত অংশগুলি উদ্ধৃত করছে। এবং মনে হয় আপনি ইতিমধ্যে এটি সম্পর্কে জানেন।
উত্সাহক

3
আমি নিশ্চিত না যে আপনি এখানে কী ধরনের উত্তর খুঁজছেন তা আমি বুঝতে পেরেছি। সি ++ অবজেক্ট মডেলটি এটি। বিধিনিষেধটি এখানে রয়েছে কারণ অবজেক্টের মডেলটির এটির প্রয়োজন। এর বাইরে আপনি আর কী খুঁজছেন?
নিকোল বোলাস

@ টবিস্পাইট একই ধরণের বিভিন্ন পৃথক পৃথকের পৃথক ঠিকানা থাকতে হবে এমন একটি প্রোগ্রামে এই নিয়মটি সুনির্দিষ্ট-সংজ্ঞায়িত আচরণ সহ সহজেই ভাঙ্গা সম্ভব।
ভাষা আইনজীবী

@ টবিস্পাইট নং, এর অর্থ এই নয় যে আপনি জীবনকাল সম্পর্কে বলতে ভুলে গিয়েছিলেন: "একই জীবনকাল সহ একই ধরণের বিভিন্ন বিষয় " । একই ঠিকানার একাধিক অবজেক্ট, সমস্ত জীবিত, একই ঠিকানায় পাওয়া সম্ভব। এটির অনুমতি দিয়ে শব্দটিতে কমপক্ষে 2 টি বাগ রয়েছে।
ভাষা আইনজীবী

উত্তর:


4

ঠিক আছে, মনে হচ্ছে এটি আমার সবসময় ভুল ছিল, যেহেতু আমার সমস্ত উদাহরণগুলির জন্য বেস অবজেক্টের জন্য একটি vtable উপস্থিত থাকা দরকার যা খালি বেস অপ্টিমাইজেশনটি শুরু করতে বাধা দেয়। আমি উদাহরণগুলি দাঁড়াতে দেব যেহেতু আমি মনে করি তারা অনন্য ঠিকানাগুলি কেন সাধারণত ভাল জিনিস হয় তার কিছু আকর্ষণীয় উদাহরণ দেয়।

এটিকে আরও গভীরতার সাথে অধ্যয়ন করার পরে, যখন প্রথম সদস্যটি খালি বেস শ্রেণীর মতো একই ধরণের হয় তখন খালি বেস শ্রেণির অপ্টিমাইজেশনের কোনও প্রযুক্তিগত কারণ নেই। এটি বর্তমান সি ++ অবজেক্ট মডেলের একটি সম্পত্তি।

তবে সি ++ ২০ এর সাথে একটি নতুন বৈশিষ্ট্য থাকবে [[no_unique_address]]যা সংকলককে বলে যে একটি অ স্থিতিশীল ডেটা সদস্যের কোনও অনন্য ঠিকানা প্রয়োজন হতে পারে না (প্রযুক্তিগতভাবে বলতে গেলে এটি সম্ভাব্যভাবে ওভারল্যাপিং হচ্ছে [অন্তর্ভুক্ত] / ))।

এটি বোঝায় যে (জোর আমার)

অ স্থিতিশীল ডেটা সদস্য অন্য অ স্থিতিশীল ডেটা সদস্য বা একটি বেস শ্রেণীর ঠিকানা ভাগ করে নিতে পারে , [...]

অতএব, প্রথম ডেটা মেম্বারকে অ্যাট্রিবিউট দিয়ে খালি বেস ক্লাসের অপ্টিমাইজেশনটি "পুনরায় সক্রিয়" করতে পারে [[no_unique_address]]। আমি এখানে একটি উদাহরণ যুক্ত করেছি যা দেখায় যে এটি (এবং অন্যান্য সমস্ত ক্ষেত্রে আমি কীভাবে কাজ করতে পারি) কাজ করে।

এর মাধ্যমে সমস্যার ভুল উদাহরণ

যেহেতু মনে হয় একটি খালি শ্রেণিতে ভার্চুয়াল পদ্ধতি নাও থাকতে পারে, তৃতীয় উদাহরণটি আমাকে যুক্ত করতে দাও:

int stupid_method(Base *b) {
  if( dynamic_cast<Foo*>(b) ) return 0;
  if( dynamic_cast<Bar*>(b) ) return 1;
  return 2;
}

Bar b;
stupid_method(&b);  // Would expect 0
stupid_method(&b.foo); //Would expect 1

তবে শেষ দুটি কল একই।

পুরানো উদাহরণ (সম্ভবত খালি ক্লাসগুলিতে ভার্চুয়াল পদ্ধতি থাকতে পারে না বলে সম্ভবত প্রশ্নের উত্তর দিবেন না)

উপরের আপনার কোডটিতে (যুক্ত ভার্চুয়াল ডেস্ট্রাক্টরগুলির সাথে) নিম্নলিখিত উদাহরণটি বিবেচনা করুন

void delBase(Base *b) {
    delete b;
}

Bar *b = new Bar;
delBase(b); // One would expect this to be absolutely fine.
delBase(&b->foo); // Whoaa, we shouldn't delete a member variable.

তবে সংকলককে এই দুটি ক্ষেত্রে কীভাবে পার্থক্য করা উচিত?

এবং সম্ভবত কিছুটা কম অবদান রয়েছে:

struct Base { 
  virtual void hi() { std::cout << "Hello\n";}
};

struct Foo : Base {
  void hi() override { std::cout << "Guten Tag\n";}
};

struct Bar : Base {
    Foo foo;
};

Bar b;
b.hi() // Hello
b.foo.hi() // Guten Tag
Base *a = &b;
Base *z = &b.foo;
a->hi() // Hello
z->hi() // Guten Tag

তবে শেষ দুটিটি একই যদি আমাদের খালি বেস শ্রেণির অপ্টিমাইজেশন থাকে!


1
একজন তর্ক করতে পারে যে দ্বিতীয় কলটি যাইহোক, যদিও নির্ধারিত আচরণ করে। তাই সংকলক কিছু আলাদা করতে হবে না।
গল্পগ্রাহক - আনস্ল্যান্ডার মনিকা

1
কোনও ভার্চুয়াল সদস্য সহ একটি বর্গ খালি নয়, এখানে অপ্রাসঙ্গিক!
Deduplicator

1
@ উত্সাহক আপনার কি এতে কোনও স্ট্যান্ডার্ড উক্তি আছে? সিপ্রেফ আমাদের জানান যে একটি খালি শ্রেণি হল "এমন একটি শ্রেণি বা কাঠামো যার কোনও স্ট্যাটাসহ ডেটা সদস্য নেই"।
n314159

1
cppreferences- std::is_emptyএ @ n314159 অনেক বেশি বিস্তৃত। Eel.is এ বর্তমান খসড়া থেকে একই ।
উত্সাহক

2
আপনি dynamic_castযখন পলিমারফিক না হন তখন আপনি পারবেন না (ছোট ব্যতিক্রমগুলি এখানে প্রাসঙ্গিক নয়)।
টিসি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.