क्यूटी में मेमोरी प्रबंधन?


96

मैं क्यूटी के लिए काफी नया हूं और स्मृति प्रबंधन और वस्तुओं के जीवन के साथ कुछ बुनियादी चीजों पर सोच रहा हूं। मुझे अपनी वस्तुओं को हटाने और / या नष्ट करने की आवश्यकता कब है? क्या इनमें से कोई भी स्वचालित रूप से नियंत्रित होता है?

नीचे दिए गए उदाहरण में, मैं किन वस्तुओं को बनाता हूं जिन्हें मुझे हटाने की आवश्यकता है? नष्ट myOtherClassहोने पर आवृत्ति चर का क्या होता है myClass? यदि मैं अपनी वस्तुओं को नष्ट (या नष्ट) नहीं करता तो क्या होगा? क्या यह स्मृति के लिए एक समस्या होगी?

MyClass.h

class MyClass
{

public:
    MyClass();
    ~MyClass();
    MyOtherClass *myOtherClass;
};

MyClass.cpp

MyClass::MyClass() {
    myOtherClass = new MyOtherClass();

    MyOtherClass myOtherClass2;

    QString myString = "Hello";
}

जैसा कि आप देख सकते हैं यह काफी नौसिखिया-आसान सामान है लेकिन मैं इस बारे में आसान तरीके से कहां सीख सकता हूं?

जवाबों:


100

यदि आप अपने स्वयं के पदानुक्रम को QObjects के साथ बनाते हैं , अर्थात, आप QObjectएक माता-पिता के साथ सभी नए बनाए गए एस को इनिशियलाइज़ करते हैं ,

QObject* parent = new QObject();
QObject* child = new QObject(parent);

तो यह करने के लिए पर्याप्त है , क्योंकि रों नाशक को नष्ट करने का ख्याल रखना होगा । (यह संकेत जारी करके ऐसा करता है, इसलिए यह तब भी सुरक्षित है जब आप माता-पिता से पहले मैन्युअल रूप से हटाते हैं ।)deleteparentparentchildchild

आप पहले बच्चे को हटा भी सकते हैं, ऑर्डर मायने नहीं रखता। एक उदाहरण के लिए जहां ऑर्डर मायने रखता है यहां ऑब्जेक्ट पेड़ों के बारे में प्रलेखन है

यदि आपका MyClassबच्चा नहीं है QObject, तो आपको चीजों को करने के सादे C ++ तरीके का उपयोग करना होगा।

इसके अलावा, ध्यान दें कि QObjectआमतौर पर माता-पिता की संतान पदानुक्रम C ++ श्रेणी के पदानुक्रम / वंशानुक्रम के पेड़ के पदानुक्रम से स्वतंत्र होती है। इसका मतलब है, कि एक निर्धारित बच्चे को माता-पिता के प्रत्यक्ष उपवर्ग होने की आवश्यकता नहीं है । कोई भी (उपवर्ग) QObjectपर्याप्त होगा।

हालाँकि, अन्य कारणों से निर्माणकर्ताओं द्वारा थोड़े बहुत अवरोध उत्पन्न किए जा सकते हैं; जैसे कि QWidget(QWidget* parent=0), जहां माता-पिता को एक और होना चाहिए QWidget, जैसे दृश्यता झंडे के कारण और क्योंकि आप इस तरह से कुछ बुनियादी लेआउट करेंगे; लेकिन सामान्य तौर पर Qt की पदानुक्रम प्रणाली के लिए, आपको QObjectमाता-पिता के रूप में कोई भी होने की अनुमति है ।


21
(It does this by issuing signals, so it is safe even when you delete child manually before the parent.)-> यह सुरक्षित नहीं है यही कारण नहीं है। Qt 4.7.4 में, QObject बच्चों को सीधे हटा दिया जाता है (के माध्यम से delete, qobject.cpp, लाइन 1955 देखें)। बाल वस्तुओं को हटाने के लिए सबसे पहले सुरक्षित होने का कारण यह है कि एक QObject अपने माता-पिता से कहता है कि इसे हटाए जाने पर इसे भूल जाएं।
मार्टिन हेनिंग्स

5
मैं यह जोड़ना चाहता हूं कि आपको यह सुनिश्चित करने के लिए वंशजों के विनाशकों को आभासी होना चाहिए। अगर ClassBविरासत में मिली है QObjectऔर ClassCविरासत में मिली है ClassB, तो ClassCकेवल क्यूटी के माता-पिता के बच्चे के रिश्ते को ठीक से नष्ट कर दिया जाएगा यदि ClassBविध्वंसक आभासी है।
फुलेसी

1
उत्तर में लिंक अब टूट गया है (लगभग 4 साल बाद आश्चर्यचकित नहीं ...), शायद यह कुछ इस तरह था qt-project.org/doc/qt-4.8/objecttrees.html ?
पीटरसन

2
@Phlucious QObject का विध्वंसक पहले से ही आभासी है, जो हर उपवर्ग के विध्वंसक को स्वचालित रूप से आभासी बनाता है।
रबनेव

1
यदि वंशानुक्रम में कहीं एक कक्षा में एक आभासी विध्वंसक है, तो नीचे के प्रत्येक बच्चे के वर्ग में एक आभासी विध्वंसक होगा। अब, अगर वर्चुअल डिस्ट्रक्टर के बिना ऐसी वर्चुअल डिस्ट्रक्टर चेन के बाहर लीफ पैरेंट क्लास है, तो मेरा मानना ​​है कि आपके पास उस विशिष्ट वर्ग के पॉइंटर को डिलीट करने पर समस्या हो सकती है जब वास्तविक ऑब्जेक्ट कहीं और उस चेन से नीचे हो। QObject के एक बच्चे के वर्ग के मामले में और उस बाल वर्ग के एक उदाहरण के लिए QObject पॉइंटर को हटाने के मामले में, कभी भी कोई समस्या नहीं होती है, भले ही आप उस उपवर्ग के विध्वंसक घोषणा में वर्चुअल कीवर्ड को भूल जाएं।
रूबनेव

47

मैं देबिल्स्की के उत्तर का विस्तार करना चाहूंगा कि क्यूटी में स्वामित्व की अवधारणा बहुत महत्वपूर्ण है। जब क्लास ए कक्षा बी का स्वामित्व मान लेता है, तो क्लास ए हटा दिए जाने पर क्लास बी हटा दिया जाता है। ऐसी कई स्थितियाँ हैं जहाँ एक वस्तु दूसरे का मालिक बन जाती है, न कि केवल तब जब आप एक वस्तु बनाते हैं और उसके अभिभावक को निर्दिष्ट करते हैं।

उदाहरण के लिए:

QVBoxLayout* layout = new QVBoxLayout;
QPushButton someButton = new QPushButton; // No owner specified.
layout->addWidget(someButton); // someButton still has no owner.
QWidget* widget = new QWidget;
widget->setLayout(layout); // someButton is "re-parented".
                           // widget now owns someButton.

एक और उदाहरण:

QMainWindow* window = new QMainWindow;
QWidget* widget = new QWidget; //widget has no owner
window->setCentralWidget(widget); //widget is now owned by window.

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

जैसा कि डेबिल्स्की द्वारा कहा गया है, ये नियम केवल उन वस्तुओं पर लागू होते हैं जो QObject से प्राप्त होते हैं। यदि आपकी कक्षा QObject से नहीं निकलती है, तो आपको खुद को नष्ट करना होगा।


लेखन के बीच अंतर को Whats: QPushButton * someButton = new QPushButton (); या QPushButton someButton = नया QPushButton या सिर्फ QPushButton someButton;
मार्टिन

3
एह, QPushButton * someButton = new QPushButton के बीच बहुत बड़ा अंतर है; और QPushButton someButton ;; पूर्व ढेर पर ऑब्जेक्ट को आवंटित करेगा, जबकि बाद वाला इसे स्टैक पर आवंटित करेगा। QPushButton * someButton = new QPushButton () के बीच कोई अंतर नहीं है; और QPushButton someButton = new QPushButton ;, ये दोनों ऑब्जेक्ट के डिफॉल्ट कंस्ट्रक्टर को कहेंगे।
ऑस्टिन

मुझे यह पूछने के लिए बहुत खेद है, लेकिन "ढेर पर वस्तु आवंटित" और "इसे ढेर पर आवंटित" के बीच क्या अंतर है? मुझे कब ढेर का उपयोग करना चाहिए और कब स्टैक का उपयोग करना चाहिए? धन्यवाद!
मार्टिन

3
आपको गतिशील आवंटन, ऑब्जेक्ट स्कोप और RAII के बारे में पढ़ना होगा। सादे C ++ के मामले में, आपको जब भी संभव हो तब वस्तुओं को स्टैक पर आवंटित करना चाहिए क्योंकि जब वे गुंजाइश से बाहर निकलते हैं तो ऑब्जेक्ट स्वचालित रूप से नष्ट हो जाते हैं। वर्ग के सदस्यों के लिए, प्रदर्शन के कारण ढेर पर वस्तुओं को आवंटित करना बेहतर होता है। और जब भी आप किसी फ़ंक्शन / विधि के निष्पादन को "आउटलाइव" करने के लिए ऑब्जेक्ट चाहते हैं, तो आपको ऑब्जेक्ट को हीप पर आवंटित करना चाहिए। फिर, ये बहुत महत्वपूर्ण विषय हैं जिन्हें कुछ पढ़ने की आवश्यकता है।
ऑस्टिन

@ ऑस्टिन सामान्य कथन जिसे आपको प्रदर्शन के लिए ढेर पर वर्ग के सदस्यों को आवंटित करना चाहिए, बैलगाड़ी है। यह वास्तव में निर्भर करता है और आपको स्वचालित भंडारण अवधि के साथ चर पसंद करना चाहिए जब तक कि आपको गड़बड़ी की समस्या न हो।
रबनेव

7

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

QObject* parent = new QObject();
QObject* child = new QObject(parent);
delete parent;//all the child objects will get deleted when parent is deleted, child object which are deleted before the parent object is removed from the parent's child list so those destructor will not get called once again.

स्मार्टपॉइंटर का उपयोग करते हुए, क्यूटी में मेमोरी को प्रबंधित करने के अन्य तरीके हैं। निम्नलिखित लेख Qt में विभिन्न स्मार्ट पॉइंटर्स का वर्णन करता है। https://blog.qt.digia.com/blog/2009/08/25/count-with-me-how-many-smart-pointer-classes-does-qt-have/


-2

इन उत्तरों को जोड़ने के लिए, वैरिफिकेशन के लिए, मैं आपको Visual Leak Detetorअपने विज़ुअल c ++ प्रॉजेक्ट्स के लिए लाइब्रेरी का उपयोग करने की सलाह दूंगा, क्यूटी प्रोजेक्ट्स सहित, c ++ पर आधारित है, यह लाइब्रेरी new, delete, free and mallocस्टेटमेंट्स के अनुकूल है , यह अच्छी तरह से प्रलेखित और उपयोग में आसान है। यह मत भूलो कि जब आप अपना खुद का QDialogया QWidgetविरासत में मिला इंटरफ़ेस क्लास बनाते हैं, और फिर इस वर्ग का एक नया ऑब्जेक्ट बनाते हैं, तो setAttribute(Qt::WA_DeleteOnClose)अपनी ऑब्जेक्ट के फ़ंक्शन को निष्पादित करना न भूलें ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.