2010-08-18 10 views
16
class A; 

class B { 
public: 
    B(A& a) : a(a) {} 
private: 
    A& a; 
}; 

/* Method 1 */ 
/* warning C4355: 'this' : used in base member initializer list */ 
/* 
class A { 
public: 
    A() : b(*this) {} 

private: 
    B b; 
}; 
*/ 

/* Method 2 */ 
/* But I need to manually perform memory dellocation. */ 
class A { 
public: 
    A() { b = new B(*this); } 
    ~A() { delete b; } 

private: 
    B* b; 
}; 

int main() { 
} 

वर्तमान में आधार सदस्य प्रारंभकर्ता सूची में प्रयोग किया जाता है, जब मैं बी में संदर्भ को प्रारंभ करने का प्रयास करें, मैं विधि 1. हालांकि, विधि 1 इच्छा झंडा मुझे चेतावनी उपयोग कर रहा हूँ जो समझ में आता हैप्रारंभ एक संदर्भ - चेतावनी C4355: 'इस':

इसलिए, मुझे गतिशील स्मृति आवंटन का उपयोग करके विधि 2 का उपयोग करके वापस गिरना होगा।

क्या मैन्युअल मेमोरी आवंटन/डेलोकेशन की आवश्यकता के बिना मैं कोई बेहतर तरीका उपयोग कर सकता हूं (ठीक है। मुझे स्मार्ट पॉइंटर पता है)?

मैं विधि 1 पसंद करता हूं, बस मुझे चेतावनी के साथ सहज नहीं है।

उत्तर

12

नोट यह एक चेतावनी है (इसलिए यह खतरनाक नहीं है)।

कंपाइलर इस बारे में चिंतित है कि आप किसी ऑब्जेक्ट के लिए पॉइंटर पास कर रहे हैं जिसे पूरी तरह से प्रारंभ नहीं किया गया है। इस प्रकार यदि बी क्लास कन्स्ट्रक्टर में पॉइंटर का उपयोग किया जाता है तो आप अपरिभाषित व्यवहार में हैं।

तो यदि आप इसका उपयोग करते हैं तो केवल एक चीज जो आप कर सकते हैं वह एक सदस्य चर (संदर्भ या सूचक) को सूचक निर्दिष्ट करता है। लेकिन ध्यान दें एक चर के लिए असाइनमेंट से सावधान रहें क्योंकि आप एक निहित कलाकार का आह्वान कर सकते हैं (मुझे यकीन नहीं है कि यह वास्तव में एक समस्या है लेकिन आरटीटीआई तब तक उपलब्ध नहीं है जब तक ऑब्जेक्ट पूरी तरह से गठित न हो)।

संदर्भ को संग्रहीत करके आप क्या हासिल करने की कोशिश कर रहे हैं?

8

ऐसा करना मान्य है।

हालांकि, आपको यह सुनिश्चित करना होगा (मेरा मतलब है कि कंपाइलर ऐसा कर सकता है) कि this का उपयोग वर्चुअल फ़ंक्शंस को कॉल करने के लिए नहीं किया जाता है जब तक ऑब्जेक्ट पूरी तरह से निर्मित नहीं होता है।

1

ठीक है, चेतावनी से बचने का एक स्पष्ट तरीका बी को एक पॉइंटर-टू-ए स्टोर करना है, तो आपको बी के कन्स्ट्रक्टर/ए की प्रारंभिक सूची में इसे प्रारंभ करने की आवश्यकता नहीं है, और ए के शरीर तक प्रतीक्षा कर सकते हैं कन्स्ट्रक्टर निष्पादित कर रहा है ....

0

इस चेतावनी को गंभीरता से लें। आपका this ऑब्जेक्ट अभी तक पूरी तरह से निर्मित नहीं हुआ है और चारों ओर गुज़रना सुरक्षित नहीं है (यदि आपने कभी गलती से this पर फ़ंक्शन को कॉल किया है तो आप यूबी का आह्वान करते हैं)। इसके अलावा, स्मृति प्रबंधन के लिए अन्य तकनीकें भी हैं। आवंटकों के एसटीएल डिजाइन को देखने का प्रयास करें।

आप उसी प्रभाव को प्राप्त करने के लिए आरएआईआई/स्मार्ट पॉइंटर्स का भी उपयोग कर सकते हैं।

या, क्या आप एक कचरा कलेक्टर/मेमोरी प्रोफाइलर लिखने की कोशिश कर रहे हैं?

6

आप जो कर रहे हैं उसके आधार पर, A के हिस्सों को कारगर करने के लिए एक विधि हो सकती है कि B की आवश्यकता है, A भाग से प्राप्त करने के लिए।

struct bar_base; // interface foo wants 

struct foo 
{ 
    foo(bar_base& pX) : 
    mX(pX) 
    {} 

    bar_base& mX; 
}; 

struct bar_base 
{ 
    /* whatever else */ 
protected: 
    bar_base& get_base(void) 
    { 
     // getting `this` went here; safe because bar_base is initialized 
     return *this; 
    } 
}; 

struct bar : bar_base 
{ 
    bar(void) : 
    // bar_base is already initialized, so: 
    mX(get_base()) 
    {} 

    foo mX; 
}; 

जाहिर है, यह इस बात पर निर्भर करता है कि आप क्या कर रहे हैं। यह सुनिश्चित करता है कि आपको कभी भी अपरिभाषित व्यवहार न मिले।

लेकिन वास्तव में, यह केवल चेतावनी है।तुम कभी नहीं बी के निर्माता में this उपयोग करने के लिए वादा करता हूँ, तो तुम ठीक हो, और चेतावनी इस तरह से मौन कर सकते हैं:

struct bar; 

struct foo 
{ 
    foo(bar& pX) : 
    mX(pX) 
    {} 

    bar& mX; 
}; 

struct bar 
{ 
    bar(void) : 
    mX(self()) 
    {} 

    foo mX; 

private: 
    bar& self(void) 
    { 
     // fools the warning 
     return *this; 
    } 
}; 

, सुनिश्चित करें कि आप जानते हैं कि आप क्या कर रहे हैं, हालांकि। (शायद इसे फिर से डिजाइन किया जा सकता है?)

संबंधित मुद्दे