2010-12-17 21 views
6

मैं विंडोज़ में कुछ कोड पोर्ट कर रहा हूं और स्टंप हो गया हूं। कुछ कोड है जो पॉइंटर को पॉइंटर पर कॉपी करने के लिए स्वचालित रूप से लॉन्च पर चलता है, और पॉइंटर को पॉइंटर को हटाने के लिए बाहर निकलने पर फिर से चला जाता है यदि यह शून्य नहीं है।पॉइंटर-टू-पॉइंटर क्रैश होता है जहां पॉइंटर

मैं व्यवहार

int main() 
{ 
    // Pointer to a Pointer, current crash. 
    InterfaceClass** ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = (InterfaceClass**)(&object); // cast is required for some reason. 
    delete *ptrptr; // Crash here. 

    // Single pointer, works fine. 
    InterfaceClass* ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = object; 
    delete ptrptr; 

    // There are other cases where there are only 3 classes in the hierarchy. 
    // This also works fine. 
    InterfaceClass** ptrptr; 
    ConcreteOne* object = new ConcreteOne(); 
    ptrptr = (InterfaceClass**)(&object); 
    delete *ptrptr; 

    return 0; 
} 

वर्ग पदानुक्रम इस तरह दिखता है पुन: पेश करने के लिए एक नमूना कार्यक्रम बनाया है। बेस क्लास कुछ शुद्ध आभासी कार्यों के साथ एक इंटरफ़ेस है और इस कार्यक्रम में कई कक्षाओं द्वारा इस तरह से शामिल किया गया है कि कई ऑब्जेक्ट्स संभावित रूप से इसे एक से अधिक स्थानों से प्राप्त करते हैं। इस वजह से ठोस कार्यान्वयन को इसे "सार्वजनिक वर्चुअल इंटरफेस क्लास" के साथ विस्तारित करना होगा। इस उदाहरण में "आभासी" को हटाने से दुर्घटना हल हो जाती है।

class InterfaceClass { 
public: 
    virtual ~InterfaceClass() {}; 
    InterfaceClass() {} 
}; 

class ConcreteClass : public virtual InterfaceClass { 
public: 
    ConcreteClass() { } 
    virtual ~ConcreteClass() {} 
}; 

class ConcreteOne : public ConcreteClass 
{ 
public: 
    ConcreteOne(void) {} 
    virtual ~ConcreteOne(void) {} 
}; 

class ConcreteTwo : public ConcreteOne 
{ 
public: 
    ConcreteTwo(void) {} 
    virtual ~ConcreteTwo(void) {} 
}; 

उत्तर

5

तो क्या आप इस तथ्य से परिचित हैं कि पॉइंटर के प्रकार के बारे में कुछ भी करने के लिए शायद ही कुछ करना है? दूसरे शब्दों में, जहां आप इस धारणा के तहत हैं कि यदि टी 1 टी 2 से विरासत में आता है तो टी 1 * भी टी 2 * से प्राप्त होता है? यह गलत होगा। अब, यह आपकी वर्तमान स्थिति पर कैसे लागू होता है?

InterfaceClass** ptrptr; 
    ConcreteTwo* object = new ConcreteTwo(); 
    ptrptr = (InterfaceClass**)(&object); // cast is required for some reason. 

यहाँ सी शैली कास्टिंग के साथ एक बड़ी समस्या है। ठीक है, तो यह कुछ क्षैतिज जगह बचाता है लेकिन क्या आप यह भी जानते हैं कि आपने किस तरह का कलाकार बनाया है? ऐसा नहीं है कि आप क्या सोचते हैं। आपने वास्तव में reintpret_cast को कंक्रीटटवो * से एक असंबंधित प्रकार इंटरफ़ेस क्लास * पर किया है! अब सूचक पते के पास उस प्रकार के साथ कुछ लेना देना नहीं है जिसे आप कहते हैं।

फिर आप एक पुनरावर्तित सूचक प्रकार को हटाने में टॉस करते हैं, जो तुरंत आपको अपने स्वयं के स्फिंकर का उल्लंघन करने का कारण बनता है।

3

ठीक है, संकलक आप चेतावनी दी, आप इसे अपने तरीके से करना का फैसला किया ...

आप इस डाली नहीं कर सकता: ConcreteTwo को

ptrptr = (InterfaceClass**)(&object); 

क्योंकि object अंक है, जो InterfaceClass जैसा नहीं है। InterfaceClassConcreteTwo का उप-ऑब्जेक्ट एक अलग पते पर स्थित है। *ptrptrInterfaceClass के उदाहरण के लिए एक सूचक नहीं है।

आपके द्वारा delete पर जाने वाला पॉइंटर ConcreteTwo पर एक सूचक है, हालांकि आपने संकलक से कहा कि यह InterfaceClass पर सूचक है। delete मानता है कि यह वास्तव में InterfaceClass है, इसलिए दुर्घटना।

1

मुझे लगता है कि समस्या कास्ट लाइनों में हैं। बीटीडब्लू, अगर आप डाली को हटाते हैं तो आपने कंपाइलर को ठीक से बताया है कि समस्या क्या है।

तुम सच में इस तरह से है, जो मैं दृढ़ता के खिलाफ सलाह करने के लिए, चाहते हैं तो आपको पहले एक अस्थायी बनाना चाहिए:

ConcreteTwo* object = new ConcreteTwo(); 
InterfaceClass* ptr = object; 

तो आप इसका पता लेने के लिए और ptrptr चर को असाइन कर सकें:

InterfaceClass** ptrptr = &ptr; 

अब आप सुरक्षित रूप से इसे हटा सकते हैं:

delete *ptrptr; 

ध्यान रखें कि ptrptrptr से पहले दायरे से बाहर हो जाता है, तो डिलीट शायद फिर से क्रैश हो जाएगा।

बाकी के लिए, नूह आपको बताता है कि आपका कोड क्यों काम नहीं कर रहा है।

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