কেন কোনও ভেটেবল পয়েন্টারের সাথে সদৃশ খালি বেস ওভারল্যাপের জন্য সঞ্চয়স্থান নেই?


11

এই উদাহরণ বিবেচনা করুন:

#include <iostream>

int main()
{
    struct A {};
    struct B : A {};
    struct C : A, B {};

    std::cout << sizeof(A) << '\n'; // 1
    std::cout << sizeof(B) << '\n'; // 1
    std::cout << sizeof(C) << '\n'; // 2, because of a duplicate base

    struct E : A {virtual ~E() {}};
    struct F : A, B {virtual ~F() {}};

    std::cout << sizeof(E) << '\n'; // 8, the base overlaps the vtable pointer
    std::cout << sizeof(F) << '\n'; // 16, but why?
}

(গডবোল্টে চালানো)

এখানে আপনি দেখতে পারেন যে struct Eখালি বেস শ্রেণীর জন্য (যা 1 বাইট বৃহত্তর) প্রত্যাশার মতো vtable পয়েন্টার হিসাবে একই স্টোরেজটি ব্যবহার করে।

তবে struct Fযার ডুপ্লিকেট খালি বেস রয়েছে, এটি ঘটে না। এর কারণ কী?

আমি জিসিসি, কলং এবং এমএসভিসিতে একই ফলাফল পেয়েছি। উপরের ফলাফলগুলি x64 এর জন্য, তাই sizeof(void *) == 8


মজার বিষয় হচ্ছে, struct G : A, B {void *ptr;};জিসিসি এবং ক্ল্যাংয়ের জন্য ইবিও করেন (আকারটি 8) তবে এমএসভিসি তা করে না (আকার 16)।


3
স্ট্রেঞ্জলি, থেকে inheriting দ্বারা C(যার থেকে উত্তরাধিকারী A, B) আপনি কি ফর্মটি inheriting চেয়ে ভিন্ন ফলাফল পেতে Aএবং Bসরাসরি
Guillaume, Racicot

1
আমি এই গবেষণা উপভোগ করেছি। প্রশ্ন এবং লিঙ্কের জন্য ধন্যবাদ। আমি নিশ্চিত না আমার একটি উত্তর আছে এবং তাই কেবল মন্তব্য করবে। এটা কি হতে পারে যে, এই অস্পষ্টতা আহরণ থেকে চালু থেকে দেখা দেয় দুটো কারণে Cএবং F? সর্বোপরি, 2 * sizeof(void*) == 16x86_64 তে যেমন আপনি বলেছেন। সংকলক সম্পূর্ণরূপে অনুকূলিত করতে পারে না (স্টোরি টেলার যেমন বলেছিল) এবং তেমনটি করে না।
অ্যান্ড্রু ফালাঙ্গা

2
এটি একেবারেই সাধারণ যে আপনি জিসিসি এবং বিড়ম্বনায় একই ফলাফল পেয়েছেন, যেহেতু তারা উভয়ই এটিবিয়াম এবিআই অনুসরণ করে। এবং যদি আমার মনে হয় এবিআই সংজ্ঞা দেওয়ার সময় তারা ভয় পেয়েছিল যে লেআউটটি অ্যালগরিদম খুব ব্যয়বহুল হয়ে উঠতে পারে, তাই তারা কিছু শর্টকাট নিয়েছে (ওরফে হতাশা)।
মার্ক গ্লিস

2
@ রিয়ানকুইন একটি সদৃশ বেস কোনও কাঠামোকে অবৈধ করে না।
হলিব্ল্যাকগেট

1
@ রিয়ানকুইন একই শ্রেণীর একাধিকবার বিভিন্ন "পাথ" এর মাধ্যমে উত্তরাধিকার সূত্রে সি ++ এ পুরোপুরি বৈধ। আপনি যদি কোনও হীরক কাঠামো তৈরি করতে চান, যেমন একবারে বেস ক্লাসটি থাকে তবে আপনাকে ভার্চুয়াল উত্তরাধিকার ব্যবহার করতে হবে। তবে যদি আপনি হীরা চান না এবং ডুপ্লিকেট বেস ক্লাসটি আপনার পক্ষে কোনও সমস্যা না হয় তবে ভাষার পক্ষে এটি কোনও সমস্যা নয়। ওপির কোডটি কেবল একটি সতর্কতা তৈরি করে বলে যে দ্বিতীয়টি Aউত্তরাধিকার সূত্রে প্রাপ্ত B, অ্যাক্সেস করা যায় না। ওটা দারুন. আপনার উদাহরণ হিসাবে যেমন আপনি যদি এটি অ্যাক্সেস করার চেষ্টা করেন তবেই আপনি একটি ত্রুটি পান।
সেব্রোকম

উত্তর:


4

কারণ সংকলক স্ট্রাক্ট এ এর ​​পরে একটি বাইট প্যাডিং যুক্ত করে

এফ 1 টি প্যাডিং থেকে এফ {ভিপিটিআর (8) + 0 জন সদস্য (কারণ খালি খালি) +} = 9 থেকে +0 তারপরে সংকলক কাঠামোর স্টোরেজটি সারিবদ্ধ করতে 7 বাইট প্যাডিং যুক্ত করুন;

E {vptr (8) + 0 এর জন্য A} = 8 প্যাডিংয়ের প্রয়োজন নেই

মাইক্রোসফ্ট থেকে

প্রতিটি ডেটা অবজেক্টের একটি প্রান্তিককরণ-প্রয়োজনীয়তা রয়েছে। কাঠামোর জন্য, প্রয়োজনীয়তা তার সদস্যদের মধ্যে বৃহত্তম। প্রতিটি অবজেক্ট একটি অফসেট বরাদ্দ করা হয় যাতে অফসেট% প্রান্তিককরণ-প্রয়োজনীয়তা == 0 হয়

https://docs.microsoft.com/en-us/cpp/c-language/storage-and-alignment-of-structures?view=vs-2019

সম্পাদনা করুন:

এখানে আমার ডেমো:

int main()
{
    C c;
    A* a = &c;
    B* b = &c;

    std::cout << sizeof(A) << " " << a << '\n'; 
    std::cout << sizeof(B) << " " << b << '\n'; 
    std::cout << sizeof(C) << " " << &c << '\n'; 

    E e;
    a = &e;
    std::cout << sizeof(E) <<" " << &e << " " << a << '\n'; 

    F f;
    a = &f;
    b = &f;
    std::cout << sizeof(F) << " " << &f << " " << a << " " << b << '\n';

}

আউটপুট:

1 0000007A45B7FBB4
1 0000007A45B7FBB5
1 0000007A45B7FBB4
8 0000007A45B7FC18 0000007A45B7FC20
16 0000007A45B7FC38 0000007A45B7FC40 0000007A45B7FC41

যেমন আপনি দেখতে পাচ্ছেন যে & বি কখনই একে অপরের সাথে এবং একাধিক উত্তরাধিকারে ভিটিপিআর দিয়ে ওভারল্যাপ হয় না যার প্রত্যেকটির নিজস্ব পয়েন্টার মান রয়েছে

VC2019 x64 বিল্ড দ্বারা সংকলিত নোট


আমি মনে করি না এটি এইভাবে কাজ করে। Aসদস্য না থাকলেও এটি এখনও 1 বাইট (যা অন্য কোনও বস্তুর সাথে ভাগ করা যায়) দখল করে। ইন E, Avptr এর পরে অবস্থিত নয়; এটি ভিটিপিআর এর প্রথম বাইটকে ওভারল্যাপ করে। (এখানে একটি ডেমো রয়েছে ; Aঅ্যাক্সেসযোগ্য করার জন্য আমি কোডটি কিছুটা সংশোধন করেছি ))। প্রথম Aমধ্যে একই হয় F। যেহেতু A(এবং B) ভিটিপিআর শীর্ষে স্থাপন করা যেতে পারে, তবে কেন এটি হয় না তা আমি নিশ্চিত নই B
হলিব্ল্যাকগেট

@ হোলিব্ল্যাকগ্যাট তবে চেক টেস্ট কোডটি এটি ঘটেছে
আহমেদ আনটার

আহা, সুতরাং এমএসভিসি এখানে জিসিসি / কলংয়ের থেকে আলাদা আচরণ করে; এটি Aভিটিপিআর শীর্ষে রাখার মতো স্মার্ট নয় । এটি এমএসভিসিতে কেন আউটপুট 16 হয় তা ব্যাখ্যা করতে পারে তবে আমি নিশ্চিত না যে জিসিসি ও কলংয়ের সাথে কী চলছে।
হলিব্ল্যাকগেট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.