2012-03-02 17 views
12

यह प्रश्न हमेशा मुझे परेशान करता है खासकर जब मैं क्यूटी के साथ प्रोग्रामिंग कर रहा हूं। चूंकि क्यूटी ऑब्जेक्ट स्वामित्व वाले पेड़ का उपयोग करता है, एक सूचक को गुजरता है उदा। myBoostSharedPtr.get() के माध्यम से स्वामित्व स्वामित्व स्थानांतरित कर सकते हैं। अब उस मामले पर विचार करें जहां कुछ क्यूटी ऑब्जेक्ट नष्ट हो जाते हैं और पूरा ऑब्जेक्ट ट्री नष्ट हो जाता है लेकिन स्मार्ट-पॉइंटर अभी भी जिंदा है। एक अलग वर्ग के सदस्य के रूप में। क्या होता है यदि स्मार्ट-पॉइंटर बाद में हटा दिया जाता है? सभी ग़लत परिणामों के साथ डबल विलोपन? क्या कुछ स्मार्ट-पॉइंटर कार्यान्वयन इसे रोकते हैं?क्या होता है यदि किसी स्मार्ट पॉइंटर द्वारा आयोजित ऑब्जेक्ट कहीं और हटा दिया जाता है?

+1

मैं वास्तव में 'QSharedPointer' के साथ इस प्रकार की समस्या में भाग गया जो कि अवधारणात्मक रूप से बूस्ट के' shared_ptr' के समान ही है। मैंने अपने निष्कर्षों के बारे में एक ब्लॉग एंट्री लिखी: http://blog.codef00.com/2011/12/15/not-so-much-fun-with-qsharedpointer/ –

उत्तर

18

मैं क्यूटी के मेमोरी मॉडल की कमजोरियों पर एक रान करने के लिए बहुत मोहक हूं, जहां बहुत से एपीआई अभी भी कच्चे पॉइंटर्स को स्वीकार करते हैं कि क्लाइंट इसे आवंटित करता है, जबकि पॉइंटर को स्वीकार करने वाले QObject ने इसे हटा दिया है।

आपके प्रश्न का उत्तर अपरिभाषित व्यवहार है। shared_ptr में यह पता लगाने के लिए कोई तंत्र नहीं है कि क्या पॉइंटर को shared_ptr के अलावा किसी अन्य चीज़ से हटा दिया गया है, इसलिए यह आमतौर पर पॉइंटर को दूसरी बार मुक्त करने का प्रयास करेगा (लटकते पॉइंटर पर कॉल करना)। अगर आप shared_ptr का उपयोग करना चाहते हैं, तो आपको एकमात्र मेमोरी मैनेजर के रूप में shared_ptr के साथ रहना होगा। यह क्यूटी के अपने QSharedPointer के लिए भी सच है।

क्या मैं सामान्य रूप से जब क्यूटी की तरह कुछ का उपयोग कर मेरी कोड यथोचित अपवाद-सुरक्षित प्राप्त करने की कोशिश करने के लिए किया था का इस्तेमाल किया गया अब पदावनत auto_ptr (unique_ptr यह बदल देता है और यदि आप सी ++ 11 उपलब्ध ज्यादा सुरक्षित है)। यह एकमात्र ऐसा स्थान है जहां मुझे कभी भी auto_ptr का उपयोग करने का लुत्फ उठाना पड़ा, क्योंकि यह release विधि प्रदान करता है।

unique_ptr<QListWidget> widget(new QListWidget(...)); 
// do stuff with the widget to set it up for your GUI 
some_layout.addWidget(widget.release()); // <-- release ownership so that 
             // the layout now becomes responsible 
             // for memory management 
// ^^ auto_ptr works above if we don't have C++11 

आप के बाद यह पहले से ही किया जा रहा क्यूटी द्वारा स्मृति-प्रबंधित किया जाता है अपने ऑब्जेक्ट के लिए एक लगातार सूचक रखने की जरूरत है (उदा: अपने विजेट के लिए सूचक के बाद आप इसे एक लेआउट में डाला), बस एक नियमित रूप से सूचक का उपयोग । क्यूटी अब उस ऑब्जेक्ट के लिए मेमोरी मैनेजर है क्योंकि आप वास्तव में इतना बेहतर नहीं कर सकते हैं।

हालांकि, QObject::destroyed सिग्नल के माध्यम से ऑब्जेक्ट नष्ट हो जाने पर आप पता लगा सकते हैं (और इसलिए जब सूचक अमान्य हो)।

यदि आप वास्तव में परिष्कृत होना चाहते हैं, तो आप एक साझा सूचक प्रकार बना सकते हैं जो केवल QObject के उप-वर्गों को संग्रहीत करता है। चूंकि QObject एक नष्ट सिग्नल प्रदान करता है, इस प्रकार का कस्टम स्मार्ट पॉइंटर पता लगा सकता है कि QObject नष्ट सिग्नल के माध्यम से नष्ट हो गया है और ऑब्जेक्ट को दूसरी बार हटाने की कोशिश से बचें। हालांकि, यह मल्टीथ्रेड कोड में इस सिग्नल पर बालों वाली भरोसा कर सकता है, और यदि आप एक साझा सूचक को कार्यान्वित करते हैं, तो यह परमाणु संदर्भ गिनती से निपटने वाला काफी बोझ हो सकता है, पॉइंटर का निर्माण करने वाले साइट पर एक विलोपन फ़ंक्शन को कैप्चर करना (मॉड्यूल से बचने के लिए सीमा नई/बेमेल हटाना), आदि

+0

मुझे नहीं लगता कि आपको तर्क सूची में रिलीज़ होना चाहिए । अगर पॉइंटर को ले जाने से पहले 'addWidget' फेंकता है, तो आप लीक हो गए हैं। – GManNickG

+1

@GmanNickG यह एक अच्छा बिंदु है। क्या आपको लगता है कि कॉल सफल होने के बाद ही हमें रिलीज़ करना चाहिए? जिस तरह से मैं इसे देखता हूं, एपीआई ग्राहक द्वारा आवंटित स्मृति को कच्चे पॉइंटर्स स्वीकार करता है। एक बार जब मैं इसे पास करता हूं, तो मुझे लगता है कि * addwidget * में अपवाद होने पर पॉइंटर पर डिलीट करने के लिए क्यूटी की ज़िम्मेदारी है। अन्यथा यह क्यूटी लीकिंग है और जहां तक ​​मैं इसे देखता हूं, और दस्तावेज़ीकरण यह नहीं बताता है कि क्यूटी addwidget में स्थानीय प्रयास/पकड़ ब्लॉक के साथ पॉइंटर को हटाकर उस स्थिति को संभालने का प्रयास करता है या नहीं। यदि यह addWidget और rethrows में पॉइंटर को करता है और हटा देता है, तो मेरा unique_ptr हटा सकता है .. – stinky472

+0

@GManNickG ... एक लटकते सूचक पर। यह मुझे इस बात पर निर्भर करेगा कि मुझे क्या पता है कि addWidget कैसे कार्यान्वित किया जाता है। – stinky472

1

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

1

आप किसी अभिभावक QObject और एक स्मार्ट सूचक के बीच एक साझा स्वामित्व हो सकता है नहीं और अन्य को हटाने के लिए एक को रोकने, लेकिन आप केवल QWeakPointer उपयोग करके किसी भी QObject का विलोपन ट्रैक कर सकते हैं (या QPointer)।ट्रैकिंग QObjectQWeakPointer साथ QSharedPointer द्वारा प्रबंधित नहीं रहा है QPointer के पक्ष में पदावनत किया गया है (जो अपने आप undeprecated है), क्यूटी 5 के साथ:

देखें http://qt-project.org/doc/qt-4.8/qweakpointer.html#tracking-qobject

अद्यतन

+0

आपको नहीं करना चाहिए। 'QWeakPointer' के बिना 'QWeakPointer' का उपयोग करके बहुत अच्छे कारणों से बहिष्कृत किया गया था, इसी कारण यह _C++ 11_ में नहीं है। – abergmeier

+0

@abergmeier मुझे यकीन नहीं है कि आप टिप्पणी छोड़ने या यहां तक ​​कि उत्तर को अपडेट करने के बजाय आप नीचे क्यों मतदान करते हैं। 'QObject' ट्रैकिंग के उद्देश्य के लिए 'QWeakPointer' का उपयोग करना लेखन के समय अनुशंसित तरीका था। – alexisdm

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

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