2011-11-15 4 views
9

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

::std::shared_ptr इसे संभालने के लिए एक प्राकृतिक है। डीएजी को संभालने के लिए संदर्भ गणना की गई थी।

दुर्भाग्यवश, निर्भरताओं को अपने आश्रितों को जानने की आवश्यकता है - जब निर्भरता अपडेट की जाती है, तो इसे अपने सभी आश्रितों को बताने की आवश्यकता होती है।
यह एक छोटा सा चक्र बनाता है जिसे ::std::weak_ptr के साथ तोड़ दिया जा सकता है। निर्भरता सिर्फ उन आश्रितों के बारे में भूल सकती है जो दूर जाते हैं।

लेकिन मुझे निर्माण के दौरान ::std::weak_ptr बनाने के लिए एक आश्रित के लिए कोई रास्ता नहीं मिल रहा है।

यह काम नहीं करता:

object::object(shared_ptr<object> dependency) 
{ 
    weak_ptr<object> me = shared_from_this(); 
    dependency->add_dependent(me); 
    dependencies_.push_back(dependency); 
} 

नाशक में यह कोड परिणाम निर्माता रास्ते से पहले बुलाया जा रहा है।

क्या इस समस्या को संभालने का कोई अच्छा तरीका है? मैं एक सी ++ 11-केवल समाधान के साथ पूरी तरह खुश हूं।

उत्तर

9

एक निर्माता के बजाय, अपने ग्राफ के नोड्स बनाने के लिए फ़ंक्शन का उपयोग करें।

std::shared_ptr<Node> mk_node(std::vector<std::shared_ptr<Node>> const &dependencies) 
{ 
    std::shared_ptr<Node> np(new Node(dependencies)); 
    for (size_t i=0; i<dependencies.size(); i++) 
     dependencies[i].add_dependent(np);  // makes a weak_ptr copy of np 
    return np; 
} 

आप इस एक static सदस्य समारोह या अपने Node वर्ग के एक friend करते हैं, तो आप वास्तविक निर्माता private बना सकते हैं।

+2

यह 'enable_shared_from_this' पहले से ही करता है। आपको अपनी घोषणा में एक भटक * भी मिला है - आप एक shared_ptr चाहते हैं, एक साझा_ptr के लिए सूचक नहीं। :) –

+0

यह एक अच्छा जवाब है, लेकिन मेरी स्थिति में मेरे पास 'आश्रित' तर्क नहीं होगा। यह फ़ंक्शन प्रत्येक निर्भरता के आश्रितों की सूची में नव निर्मित नोड (यानी 'np') जोड़कर सभी निर्भरताओं के माध्यम से लूप करेगा। – Omnifarious

+0

@ ओमनिफरीस: उदाहरण अपडेट किया गया। –

5

असल में, आप नहीं कर सकते।बनाने के लिए आपको shared_ptr या weak_ptr की आवश्यकता है और जाहिर है कि स्वयं केवल के बारे में केवल weak_ptr के रूप में अवगत हो सकता है (अन्यथा संदर्भों की गणना करने में कोई बात नहीं है)। और, ज़ाहिर है, ऑब्जेक्ट अभी तक नहीं बनाया गया है, तो कोई self-shared_ptr नहीं हो सकता है।

1

मैं garbage collection मुद्दों से अवधारणात्मक रूप से संबंधित आपके प्रश्न को समझ रहा हूं।

जीसी एक गैर मॉड्यूलर सुविधा है: यह कार्यक्रम की कुछ वैश्विक संपत्ति से संबंधित है (अधिक सटीक रूप से, एक लाइव डेटा होने के नाते एक कार्यक्रम के अंदर एक वैश्विक, गैर-मॉड्यूलर, संपत्ति है - ऐसी स्थितियां हैं जहां आप इससे निपट नहीं सकते कि एक मॉड्यूलर & रचनात्मक तरीके से।)। AFAIK, एसटीएल या सी ++ मानक पुस्तकालय वैश्विक प्रोग्राम सुविधाओं के लिए बहुत मदद नहीं करते हैं।

एक संभावित उत्तर कचरा कलेक्टर का उपयोग (या स्वयं को लागू करना) हो सकता है; Boehm's GC आपके लिए उपयोगी हो सकता है, यदि आप इसे अपने पूरे कार्यक्रम में उपयोग करने में सक्षम हैं।

और आप अपनी समस्या से निपटने के लिए जीसी एल्गोरिदम (यहां तक ​​कि पीढ़ी वाले लोगों की प्रतिलिपि भी) का उपयोग कर सकते हैं।

+0

मैं वास्तव में नहीं देखता कि यह प्रश्न का उत्तर कैसे देता है। –

+0

आपका सबसे अधिक बॉक्स ऑफ उत्तर है, और दिलचस्प रूप से पर्याप्त है, मैंने पहले ही इसके बारे में सोचा और विचार को त्याग दिया। लेकिन हाँ ... तुम सही हो। दुर्भाग्यवश यह दूसरों के लिए पुनः उपयोग करने योग्य लाइब्रेरी के हिस्से के रूप में है, और जीसी की आवश्यकता कई सी ++ लोगों (कई बार, मुझे सहित) के लिए एक गैर स्टार्टर है। – Omnifarious

+0

@ बिलीओनेल: बेसिल सुझाव दे रहा है कि मैं 'shared_ptr' संदर्भ संख्या छोड़ देता हूं और इसके बजाय एक पूर्ण उड़ा कचरा कलेक्टर के साथ जाता हूं। – Omnifarious

0

हो सकता है कि इस में मदद मिलेगी: enable_shared_from_this जो मूल रूप से एक weak_ptr धारण से

प्राप्त करती हैं। यह आप उपयोग करना this->shared_from_this();

shared_ptr के अगर वर्ग वर्ग से विरासत देखने के लिए और का उपयोग वर्गों weak_ptr जब वस्तु की ओर इशारा करते के लिए कैसे पता की अनुमति देगा (रोकता 2 संदर्भ गिनती अलग ढंग से साझा संकेत) इसके बारे में

अधिक : cppreference

+0

मुझे नहीं लगता कि आप shared_from_this को कॉल कर सकते हैं जब तक कि पहले से ही 'shared_ptr'' का मालिक न हो; कन्स्ट्रक्टर में नहीं है। (20.7.2.4/7) –

+1

enable_shared_from_this के लिए +1 - इसे मूल रूप से 'weak_ptr' सदस्य के रूप में कार्यान्वित किया गया है जैसे ओपी वैसे भी चाहता है। –

+0

@AlanStokes: आप नहीं कर सकते। हालांकि ओपी के मामले को देखते हुए वह ऑब्जेक्ट में संग्रहीत ऑब्जेक्ट को केवल एक कमजोर पॉइंटर चाहता है, जो वास्तव में enable_shared_from_this करता है। –

1

आप नहीं कर सकते।

सबसे अच्छा मैं कन्स्ट्रक्टर को निजी बनाने और सार्वजनिक फैक्ट्री फ़ंक्शन बनाने के लिए आया हूं जो shared_ptr को एक नई वस्तु पर लौटाता है; फ़ैक्टरी फ़ंक्शन तब ऑब्जेक्ट पोस्ट-निर्माण पर एक निजी विधि को कॉल कर सकता है जो weak_ptr प्रारंभ करता है।

+0

यदि वर्ग से निकाला जाना है, तो कन्स्ट्रक्टर को निजी नहीं होना चाहिए, निजी नहीं। – Omnifarious

+0

@ ओमनिफरीस हां, ज़ाहिर है। –

1

दुर्भाग्यवश, निर्भरताओं को अपने आश्रितों को जानने की आवश्यकता है। ऐसा इसलिए है क्योंकि जब निर्भरता अद्यतन होती है, तो उसे अपने सभी आश्रितों को बताने की आवश्यकता होती है। और एक छोटा सा चक्र है। सौभाग्य से, इस चक्र को :: std :: weak_ptr के साथ तोड़ दिया जा सकता है। निर्भरता सिर्फ उन आश्रितों के बारे में भूल सकती है जो दूर जाते हैं।

ऐसा लगता है कि एक निर्भरता निर्भर नहीं हो सकती है जब तक निर्भर निर्भर न हो। (उदा। यदि आश्रित नष्ट हो जाता है, तो निर्भरता भी नष्ट हो जाती है - यही है कि एक डीएजी सभी के बाद है)

यदि ऐसा है, तो आप केवल सादे पॉइंटर्स (इस मामले में, this) को सौंप सकते हैं। यदि निर्भर व्यक्ति जीवित है, तो आपको निर्भरता के अंदर कभी भी जांच करने की आवश्यकता नहीं होगी, क्योंकि यदि निर्भर व्यक्ति की मृत्यु हो गई तो निर्भरता भी मरनी चाहिए।

सिर्फ इसलिए कि ऑब्जेक्ट का स्वामित्व किसी Share_ptr के स्वामित्व में है, इसका मतलब यह नहीं है कि सभी पॉइंटर्स स्वयं को shared_ptrs या weak_ptrs होना चाहिए - बस आपको पॉइंटर्स को अमान्य होने पर स्पष्ट अर्थशास्त्र परिभाषित करना होगा।

+0

यह ठीक होगा अगर यह इस तथ्य के लिए नहीं था कि किसी ऑब्जेक्ट में एकाधिक आश्रित हो सकते हैं। यह एक पेड़ नहीं है, एक पेड़ है। शाखाएं एक साथ वापस मिल सकती हैं, वहां कोई चक्र नहीं हो सकता है। – Omnifarious

+0

@ ओमनिफरीस: ठीक है। फिर फैक्टरी विधि आपका एकमात्र विकल्प है। यह लागू करने का एकमात्र तरीका है कि आप वास्तव में हमेशा स्थिर या स्वचालित भंडारण के बजाय 'shared_ptr' का उपयोग करके वस्तुओं का निर्माण कर रहे हैं, उदाहरण के लिए। (प्लस तरफ, आप कारखाने में make_shared द्वारा अनुकूलन के प्रकार का लाभ ले सकते हैं)। –

1

यह मुझे लगता है जैसे आप कुछ अलग वस्तुओं को भंग करने की कोशिश कर रहे हैं: एक वस्तु (डीएजी में एक नोड), और उन वस्तुओं का संग्रह प्रबंधित करना।

class DAG { 

    class node { 
     std::vector<std::weak_ptr<node> > dependents; 
    public: 
     node(std::vector<weak_ptr<node> > d) : dependents(d) {} 
    }; 

    weak_ptr<node> root; 
}; 

अब, यह सच हो सकता है कि DAG ही कभी बल्कि एक node सीधे का एक उदाहरण के साथ काम की तुलना में एक weak_ptr<node> का आयोजन करेगा। नोड के लिए, हालांकि, यह कम या ज्यादा अप्रासंगिक है। इसे किसी भी कुंजी/डेटा/आदि को बनाए रखने की जरूरत है, इसमें आश्रितों की अपनी सूची के साथ ही शामिल है।

इसी समय, DAG के अंदर यह घोंसले बनाने के लिए बहुत कम है, हम, node के लिए उपयोग को कम कर सकते हैं ताकि अन्य कोड (विशेष रूप से अगर हम node DAG करने के लिए निजी के वर्ग परिभाषा बनाने के) एक के बारे में कुछ के साथ संबंध हो गया है node। स्थिति के आधार पर, आप नोड में फ़ंक्शंस के कुछ (अधिकांश?) को हटाने जैसे चीजों को भी करना चाह सकते हैं कि संकलक डिफ़ॉल्ट रूप से जेनरेट करेगा (उदा।, डिफ़ॉल्ट ctor, copy ctor, असाइनमेंट ऑपरेटर)।

+0

यह एक दिलचस्प जवाब है।मुझे यकीन नहीं है कि मैं इस तरह अपना डिजाइन बदल सकता हूं। मैं बहु-थ्रेडिंग के लिए भविष्य/वचन-जैसी व्यवस्था को संभालने के लिए एक निर्भरता आधारित प्रणाली बनाने की कोशिश कर रहा हूं। नोड्स बहुत महत्वपूर्ण इकाइयां हैं। ओटीओएच, उन सभी नोड्स के लिए एक प्रबंधक होगा जो दिए गए धागे का हिस्सा हैं। हमम ... – Omnifarious

0

यह मुझे पागल भी चला रहा है।

मैंने चक्रों को तोड़ने के लिए पॉइंटर्स का उपयोग करने की नीति को अपनाने पर विचार किया ... लेकिन मुझे वास्तव में यह नहीं मिला है क्योंकि मुझे वास्तव में यह पसंद है कि कमजोर_प्टर का इरादा कितना स्पष्ट है जब आप इसे अपने कोड में देखते हैं (आपको पता है कि यह है चक्र तोड़ने के लिए)।

अभी मैं अपनी खुद की कमजोर_पीटीआर कक्षा लिखने की ओर झुका रहा हूं।

+0

_chuckle_ मैं कन्स्ट्रक्टर कार्यों को बनाने के लिए समाप्त हो गया। हालांकि, इसका एक अलग दिलचस्प मुद्दा है: http://stackoverflow.com/questions/8147027/how-do-i-call-stdmake-shared-on-a-class-with-only- संरक्षित-or-private-const मैं कहूंगा कि लोगों को इन चीज़ों को ढेर या एम्बेडेड ऑब्जेक्ट्स बनाने और फिर उन्हें 'shared_ptr' बनाने से रोकने का लाभ होता है। अगर लोगों ने ऐसा किया तो यह पूरे टन सामान तोड़ देगा। मुझे संदेह है कि आपके लिए भी मामला हो सकता है। – Omnifarious