जब खाली आधार वर्ग भी एक सदस्य चर है तो खाली आधार अनुकूलन क्यों वर्जित है?


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उदाहरण के पते के समान होगा, जैसे कि अन्य स्थितियों में होना आवश्यक है (1) । सब के बाद, मैं virtualविरासत के साथ कुछ भी कल्पना नहीं कर रहा हूं, बेस कक्षाएं परवाह किए बिना खाली हैं, और संकलन से Base2पता चलता है कि इस विशेष मामले में कुछ भी नहीं टूटता है।

लेकिन स्पष्ट रूप से यह तर्क किसी भी तरह से गलत है, और ऐसी अन्य परिस्थितियां हैं जहां इस सीमा की आवश्यकता होगी।

मान लें कि उत्तर C ++ 11 या नए के लिए होना चाहिए (मैं वर्तमान में C ++ 17 का उपयोग कर रहा हूं)।

(1) नोट: EBO C ++ 11 में अपग्रेड हो गया, और इन- StandardLayoutTypeएस के लिए विशेष रूप से अनिवार्य हो गया (हालांकि Bar, ऊपर, यह नहीं है StandardLayoutType)।


4
आपके द्वारा उद्धृत किए गए तर्क (" एक ही प्रकार के दो आधार उपविषयों के लिए अलग-अलग पते होना आवश्यक है ") कैसे कम होता है? एक ही प्रकार की विभिन्न वस्तुओं के लिए अलग-अलग पते की आवश्यकता होती है, और यह आवश्यकता सुनिश्चित करती है कि हम उस नियम को न तोड़ें। तो खाली आधार अनुकूलन यहां लागू किया है, हम हो सकता है Base *a = new Bar(); Base *b = a->foo;के साथ a==bहै, लेकिन aऔर bस्पष्ट रूप से विभिन्न वस्तुओं (शायद अलग आभासी विधि ओवरराइड के साथ) कर रहे हैं।
टोबी स्पाईट

1
भाषा-वकील का जवाब कल्पना के प्रासंगिक हिस्सों को उद्धृत कर रहा है। और ऐसा लगता है कि आप इसके बारे में पहले से ही जानते हैं।
डेडुप्लिकेटर

3
मुझे यकीन नहीं है कि मुझे समझ में आया कि आप किस तरह का उत्तर ढूंढ रहे हैं। C ++ ऑब्जेक्ट मॉडल वह है जो यह है। प्रतिबंध वहां है क्योंकि ऑब्जेक्ट मॉडल को इसकी आवश्यकता है। उससे आगे क्या देख रहे हो?
निकोल बोलस

@ टॉबीस्पाइट एक ही प्रकार की विभिन्न वस्तुओं के लिए अलग-अलग पते होना आवश्यक है। इस कार्यक्रम को अच्छी तरह से परिभाषित व्यवहार के साथ इस नियम को तोड़ना आसान है।
भाषा वकील

@TobySpeight नहीं, मेरा मतलब यह नहीं है कि आप जीवन भर के बारे में कहना भूल गए: "एक ही प्रकार की अलग-अलग वस्तु आपके जीवनकाल के साथ " । एक ही पते पर, एक ही प्रकार की कई वस्तुओं का होना संभव है। इसे अनुमति देने वाले शब्द में कम से कम 2 कीड़े हैं।
लैंग्वेज वकील

जवाबों:


4

ठीक है, ऐसा लगता है जैसे मैंने इसे हर समय गलत किया था, क्योंकि मेरे सभी उदाहरणों के लिए आधार वस्तु के लिए एक व्यवहार्य मौजूद रहने की आवश्यकता है, जो कि खाली आधार अनुकूलन को शुरू करने से रोक देगा। मैं उदाहरणों को खड़ा होने दूंगा क्योंकि मुझे लगता है कि वे कुछ दिलचस्प उदाहरण देते हैं कि क्यों अद्वितीय पते आमतौर पर एक अच्छी बात है।

इस पूरे अध्ययन का गहराई से अध्ययन करने के बाद, खाली बेस क्लास ऑप्टिमाइज़ेशन को अक्षम करने का कोई तकनीकी कारण नहीं है जब पहला सदस्य खाली बेस क्लास के समान प्रकार का हो। यह वर्तमान C ++ ऑब्जेक्ट मॉडल की एक संपत्ति है।

लेकिन सी ++ 20 के साथ एक नई विशेषता होगी [[no_unique_address]]जो संकलक को बताती है कि एक गैर-स्थैतिक डेटा सदस्य को एक अद्वितीय पते की आवश्यकता नहीं हो सकती है (तकनीकी रूप से यह संभावित रूप से अतिव्यापी है [intro.object] / 7 )।

इसका मतलब है कि (जोर मेरा)

गैर-स्थैतिक डेटा सदस्य किसी अन्य गैर-स्थैतिक डेटा सदस्य या आधार वर्ग के पते को साझा कर सकता है , [...]

इसलिए कोई पहले डेटा सदस्य को विशेषता देकर खाली आधार वर्ग अनुकूलन को "पुन: सक्रिय" कर सकता है [[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
किसी भी आभासी सदस्यों के साथ एक वर्ग खाली नहीं है, इसलिए यहाँ अप्रासंगिक है!
डेडुप्लिकेटर

1
@Deduplicator क्या आपके पास उस पर एक मानक उद्धरण है? कैप्प्रे हमें बताता है कि एक खाली वर्ग "एक वर्ग या संरचना है जिसमें कोई गैर-स्थैतिक डेटा सदस्य नहीं हैं"।
n314159

1
cppreference std::is_emptyपर @ n314159 अधिक विस्तृत है। Eel.is पर वर्तमान ड्राफ्ट से समान ।
डेडुप्लिकेटर

2
dynamic_castजब आप पॉलीमॉर्फिक नहीं हैं (मामूली अपवादों के साथ प्रासंगिक नहीं हैं)।
टीसी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.