2009-11-20 16 views
5

माइक्रोसॉफ्ट विजुअल स्टूडियो 2008 मुझे निम्न चेतावनी दे रहा है:अपूर्ण प्रकार मेमोरी लीक?

चेतावनी C4150: अधूरा प्रकार 'GLCM :: घटक' के लिए सूचक का विलोपन;

यह संभवतः इसलिए है क्योंकि मैंने कई जगहों पर घोषित प्रकारों को अग्रेषित करने के लिए हैंडल को परिभाषित किया है, इसलिए अब हैंडल क्लास का दावा है कि यह दिए गए ऑब्जेक्ट पर विनाशक को नहीं बुलाएगा।

मेरे पास वीएलडी चल रहा है और मुझे कोई रिसाव नहीं दिख रहा है। क्या यह सचमुच इस वस्तु के लिए विनाशक को नहीं बुला रहा है या यह "ऑब्जेक्ट के लिए विनाशक को कॉल नहीं कर सकता" चेतावनी है?

फिर भी एक और स्मृति रिसाव मुझसे सवाल, हाहा।

+3

"क्या यह सचमुच इस वस्तु के लिए विनाशक को नहीं बुला रहा है या यह" ऑब्जेक्ट के लिए विनाशक को कॉल नहीं कर सकता "चेतावनी है?" - आप विनाशक को प्रिंट स्टेटमेंट जोड़कर लगभग 15 सेकंड में परीक्षण कर सकते हैं। –

+0

हाहा, यह एक अच्छा मुद्दा है। धन्यवाद। – Reggie

+0

या विनाशक में एक ब्रेकपॉइंट डाल दिया। – gdunbar

उत्तर

6

यह अक्सर जब Pimpl का उपयोग कर हो, तो मैं वहाँ समाधान पर ध्यान केंद्रित करेंगे:

class FooImpl; 

class Foo 
{ 
public: 
    // stuff 
private: 
    Pimpl<FooImpl> m_impl; 
}; 

समस्या है कि यहाँ जब तक आप एक नाशक की घोषणा, यह स्वतः उत्पन्न हो जाएगा, इनलाइन, संकलक द्वारा है । लेकिन निश्चित रूप से, कंपाइलर को FooImpl के पूर्ण प्रकार का कोई जानकारी नहीं होगी।

इस प्रकार आपको निषेधकर्ता को स्पष्ट रूप से परिभाषित करना होगा, भले ही खाली हो, और परिभाषा कहीं कहीं रखें जहां FooImpl का पूरा प्रकार दिखाई दे रहा है।

// cpp file 
class FooImpl 
{ 
}; 

Foo::~Foo() {} // Empty, but now correctly generated 
       // because FooImpl complete at this point. 

इसके अलावा, अगर मेरे जैसे आप अपने Pimpl वर्ग परिभाषित (, निर्माण के बारे में कॉपी और असाइनमेंट) बहुत स्मार्ट होना करने के लिए, तो उन भी .cpp फ़ाइल में परिभाषित करने की आवश्यकता होगी।

यह वास्तव में एक परेशानी है, लेकिन फिर आपने अपने कार्यान्वयन विवरणों को अच्छी तरह से समाहित किया है, इसलिए मुझे लगता है कि यह इसके लायक है।

0

ऐसा लगता है कि आप p-implidiom का पालन नहीं कर रहे हैं।

संक्षिप्त उदाहरण:

// header 
struct Other; // declare to use a pointer to it 

struct Handle { 
    Handle(); 
    ~Handle(); 

    void f(); 

private: 
    Other* _obj; 
}; 

// implementation (.cpp) 
#include "header" 

struct Other { 
    void f(); 
}; 

Handle() : _obj(new Other()) {} 
~Handle() { delete _obj; } 

void Handle::f() { _obj->f(); } 

के बाद से हटाना का उपयोग कर वर्ग अन्य की परिभाषा के बाद अब है, प्रकार पूरा हो जाएगा। एक पूर्ण प्रकार के बिना, संकलक यह नहीं जानता कि इसे ठीक से कैसे नष्ट किया जाए। (उदाहरण के लिए dtor गैर सरकारी हो सकता है यहां तक ​​कि आभासी या गैर आभासी हो सकता है, या।)

+0

मैं टेम्पलेट हैंडल क्लास का उपयोग कर रहा हूं, तो क्या इसका मतलब है कि मुझे उस हैंडल के लिए पास किए गए प्रकार की घोषणा कभी नहीं करना चाहिए? – Reggie

+0

आह, देखें, यह महत्वपूर्ण जानकारी प्रश्न से बाहर है। :) आपको उस बिंदु पर पूरा होने की आवश्यकता होगी (और आप पी-इंप नहीं कर पाएंगे), जब तक कि आप अन्य कोनों के बीच टेम्पलेट तत्काल और विशेषज्ञता के बीच अंतर नहीं सीखना चाहते हैं। –

+0

क्या आप पी-इंप चाहते हैं? यदि ऐसा है, तो टेम्पलेट के बजाय एक गैर-टेम्पलेट का उपयोग करें। यदि नहीं, और आप एक पूर्ण प्रकार (मेरे उदाहरण में अन्य की श्रेणी परिभाषा) प्रदान नहीं कर सकते हैं, हैंडल आपके लिए कौन सी भूमिका निभाता है? –

6
सी ++ स्टैंडर्ड प्रति

(आईएसओ/आईईसी 14882: 2003 5.3.5/5):

हैं हटाए जाने वाले ऑब्जेक्ट में अपूर्ण वर्ग के प्रकार को अपूर्ण बिंदु पर रखा गया है और पूर्ण वर्ग में एक गैर-तुच्छ विनाशक या एक विलोपन समारोह है, व्यवहार अपरिभाषित है।

इसलिए, यदि आपकी कक्षा में एक गैर-तुच्छ विनाशक है, तो ऐसा न करें, इस पर ध्यान दिए बिना कि विज़ुअल सी ++ इस स्थिति को कैसे संभालता है।

class A; 

void func(A *p) 
{ 
     delete p; 
} 

int main(int argc, char **argv) 
{ 
     return 0; 
} 

चेतावनी लेकिन कोई किसी भी त्रुटि:

1

जी ++ में, चेतावनी भी निम्नलिखित कोड का उपयोग कर reproduced किया जा सकता है

test.cpp: In function void func(A*): 
test.cpp:6: warning: possible problem detected in invocation 
    of delete operator: 
test.cpp:4: warning: A has incomplete type 
test.cpp:2: warning: forward declaration of struct A 
test.cpp:6: note: neither the destructor nor the class-specific 
    operator delete will be called, even if they are declared 
    when the class is defined. 

जी ++ यहाँ बहुत स्पष्ट है कि नाशक क्योंकि कहा जाता है नहीं की जाएगी कहा गया है जबकि यह नहीं जानता कि क्या विनाशक की आवश्यकता है या नहीं, या विनाशक कहां है।

इस मामले में हटाएं() सी कॉल फ्री() को डाउनगेट करता है, यानी, यह ऑब्जेक्ट मेमोरी को ही मुक्त करता है, लेकिन ऑब्जेक्ट द्वारा आवंटित किसी भी ढेर डेटा को आंतरिक रूप से (उदाहरण के लिए, कन्स्ट्रक्टर में) रखा जाएगा, मुफ्त के समान व्यवहार (पी)।

मुझे लगता है कि यह एक समान तरीका होगा यदि एमएस वीसी/++ में; और एक सही तरीका है कि आप ए

1

के इंटरफ़ेस शीर्षलेखों को शामिल करना है, तो आपके पास हटाए जाने वाले ऑब्जेक्टर के साथ भी कोई रिसाव नहीं हो सकता है, अगर ऑब्जेक्ट को हटाया जा रहा है तो इसमें हेप-आवंटित ऑब्जेक्ट्स के पॉइंटर्स नहीं हैं। हालांकि यह कोशिश न करें - क्योंकि जेम्स मैकनेलिस his answer में उल्लेख करते हैं, यह सी ++ मानक के अनुसार अपरिभाषित व्यवहार है।

को हटाएं (स्पष्ट रूप से या स्मार्ट पॉइंटर से पहले) ऑब्जेक्ट विनाशक चलाया जाता है और फिर स्मृति को हटा दिया जाता है।वीसी ++ मूल रूप से आपको बताता है कि यह पता नहीं है कि विनाशक क्या चलाना है और इसलिए कोई भी नहीं चलाएगा बल्कि इसके बजाय स्मृति को हटा देगा। यदि ऑब्जेक्ट एक पीओडी प्रकार है या इसमें कोई पॉइंटर्स ढेर-आवंटित ऑब्जेक्ट्स पर सेट नहीं है (या तो कोई पॉइंटर्स नहीं है या इसमें किसी अन्य के स्वामित्व वाले ऑब्जेक्ट्स के लिए पॉइंटर्स शामिल हैं और इसलिए डिलीट करने की आवश्यकता नहीं है) तो रिसाव का कोई कारण नहीं है।

तो शायद वीसी ++ उसी व्यवहार का उत्पादन करेगा जैसा कि पहले ऑब्जेक्ट को void* पर कास्टिंग करेगा। लेकिन फिर इस पर भरोसा न करें - सबसे अच्छा आपके पास अयोग्य कोड होगा, जैसे ही आप अपना वीसी ++ कंपाइलर का संस्करण बदलते हैं या पैच करते हैं, उतना ही खराब होगा।

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