2011-09-27 14 views
8

यह असंभव हो सकता है, लेकिन मैं सोच रहा था कि क्या इसकी मूल अभिव्यक्ति के पीछे कभी भी अस्थायी रखना संभव था। मैं जिन वस्तुओं पर माता पिता वस्तुओं को इंगित की एक श्रृंखला है, और एक सदस्य समारोह जो एक बच्चे वस्तु पैदा करेगा, एक सरल उदाहरण यहाँ हैअपने जीवनकाल को विस्तारित करने से अस्थायी रोकें?

class person{ 
    string name; 
    person * mommy; 
public: 
    person(const string & nam, person * m = 0) : name(nam), mommy(m) {} 
    person baby(const string & nam){ 
     return person(nam, this); 
    } 
    void talk() const{ 
     if (mommy) mommy->talk(); 
     cout << name << endl; 
    } 
}; 

int main(){ 
    person("Ann").baby("Susan").baby("Wendy").talk();  // fine 

    const person & babygirl = person("Julie").baby("Laura"); // not fine 

    babygirl.talk(); // segfault 
    return 0; 
} 

तरह से मैं का उपयोग करने के person एक समारोह के लिए इसे पारित करने के लिए है चाहता हूँ, और इस तरह कुछ:

void use(const person & p) { 
    p.talk(); 
} 
use(person("Anna").baby("Lisa")); 

ठीक है।

यह तब तक ठीक काम करेगा जब तक कि कोई भी अस्थायी मूल अभिव्यक्ति से पहले जीवित रहे, लेकिन यदि मैं अंतिम अस्थायी में से किसी एक को संदर्भ में संदर्भित करता हूं, तो उसके माता-पिता जीवित नहीं रहते हैं, और मुझे एक सीगफॉल्ट मिलता है। मैं person की कॉपी कन्स्ट्रक्टर और असाइनमेंट ऑपरेटर छुपा सकता हूं, लेकिन क्या इस तरह की त्रुटि को रोकने से मैं किसी भी तरह से रोक सकता हूं? यदि संभव हो तो मैं गतिशील आवंटन से बचना चाहता हूं।

+0

@ कोनराड: आईरिकॉन; -] – ildjarn

+1

ध्यान दें कि यह कोड उसी तरह से "ठीक नहीं है" कि 'const int और i = std :: वेक्टर (1) [0]; 'लिखा नहीं है" ठीक है "। 'वेक्टर' आपको लिखने से नहीं रोकता है, और इसकी आवश्यकता नहीं है। यहां कुंजी यह है कि माँ को नष्ट करने से बच्चे को अनुपयोगी लगता है, बच्चा माँ का हिस्सा है। डिजाइन के साथ यही गलत है, यह प्रतिद्वंद्वी है। आप अनाथ के रूप में ऐसी कोई चीज़ होने से रोकने के लिए इसे पकड़ने की कोशिश कर रहे हैं, जो उचित हो सकता है लेकिन आपको यह भी विचार करना चाहिए कि अनाथों को बेहतर परिभाषित व्यवहार होना चाहिए या नहीं, या अधिक स्पष्ट रूप से बनाने के लिए एक बुरी चीज होनी चाहिए। –

+0

स्टीव के साथ सहमत: यह सिर्फ खराब डिजाइन दिखा रहा है।एक नग्न सूचक की उपस्थिति को दूर देना चाहिए था कि कुछ बंद है। –

उत्तर

3

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

क्या आपने boost::shared_ptr का उपयोग करने पर विचार किया है? यह एक संदर्भित स्मार्ट पॉइंटर वर्ग का एक कार्यान्वयन है। shared_ptr और शायद कुछ फैक्ट्री विधियों का उपयोग करके, आप जो प्रभाव चाहते हैं उसे प्राप्त करने में सक्षम हो सकते हैं और गतिशील स्मृति आवंटन के दर्द को कम कर सकते हैं। मैंने कोशिश की और ऐसा लगता है कि यह काम करता है। कोड समाप्त होने के बाद, ऑब्जेक्ट्स सभी नष्ट हो जाते हैं क्योंकि shared_ptrs को कोई संदर्भ नहीं छोड़ा जाता है।

संपादित करें: जवाब में को zounds ' टिप्पणी, मैं उदाहरण के संशोधित किया है ताकि जड़ वस्तु डेटा संरचना के जीवनकाल नियंत्रित करता है।

#include <iostream> 
#include <string> 
#include <vector> 
#include <boost\shared_ptr.hpp> 
#include <boost\weak_ptr.hpp> 

using boost::shared_ptr; 
using boost::weak_ptr; 

using std::string; 
using std::cout; 
using std::endl; 
using std::vector; 

class person; 
typedef shared_ptr<person> Person; 
typedef weak_ptr<person> PersonWk; 

class person {  
    PersonWk pThis; 
    friend Person makePerson(const string & nam, Person m = Person()); 

    string name; 
    PersonWk mommy; // children should not affect parent lifetime, so store weak ptr 
    vector<Person> children; // parents affect children lifetime so store child shared ptrs 

    // make constructor private so that you can only make a person using factory method 
    person(const string & nam, Person m) : name(nam), mommy(m) 
    { 
     // for demo purposes 
     printf("creating %s\n", nam.c_str()); 
     ++personCount; 
    } 

    // undefined copy constructor and assignment operators 
    person(const person&); 
    person& operator=(const person&); 

public: 
    // for demo purposes 
    static int personCount; 

    ~person() 
    { 
     // for demo purposes 
     printf("destroying %s\n", name.c_str()); 
     --personCount; 
    } 

    Person baby(const string & nam){   
     Person child = makePerson(nam, Person(pThis)); 
     children.push_back(child); 
     return child; 
    } 

    void talk() const{ 
     if (Person mom = mommy.lock()) 
      mom->talk(); 
     cout << name << endl; 
    } 
}; 

int person::personCount = 0; 

// factory method to make a person 
Person makePerson(const string & name, Person m) { 
    Person p = Person(new person(name, m)); 
    p->pThis = p; // stash weak_ptr so I can use it to make a shared_ptr from "this" in the baby method 
    return p; 
} 

void use(const Person p) { 
    printf("In method use...\n"); 
    p->talk(); 
} 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    printf("personCount=%d\n", person::personCount); 
    { 
     Person ann = makePerson("Ann"); 

     // ann has baby and grandbaby, pass grandbaby to use method 
     use(ann->baby("Susan")->baby("Wendy")); 

     ann.reset(); // remove reference from root object. Destruction ensues... 
    } 
    printf("personCount=%d\n", person::personCount); 
    return 0; 
} 
+0

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

+0

एक दृष्टिकोण किसी ज्ञात स्थान पर रूट ऑब्जेक्ट को स्टोर करना हो सकता है। फिर प्रत्येक माता-पिता अपने बच्चों को shared_ptrs रखता है और बच्चे कमजोर_ptrs को अपने माता-पिता को रख सकते हैं। फिर जब आप रूट ऑब्जेक्ट को न्यूल (इस प्रकार सभी संदर्भों को हटाते हैं) पर सेट करते हैं, तो पेड़ ऊपर से नीचे तक नष्ट हो जाता है। –

+0

मेरी पिछली टिप्पणी में दृष्टिकोण का उपयोग करने के लिए संशोधित कोड नमूना। –

0

आप कुछ इस तरह करना होगा:

void use(const person & p) { 
    p.talk(); 
} 
person a("Anna"); 
use(a.baby("Lisa")); 

इस तरह, माता-पिता "एक" क्षेत्र से बाहर जाना नहीं है जब तक आप वास्तव में (यह पूरे कर चुके हैं के बाद "उपयोग" पर कॉल करें)।

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

क्या यह मेरे लिए खतरनाक लग रहा है? हाँ। इसलिए मैं गतिशील आवंटन पर एम-तेज के जवाब पर एक नज़र डालने का सुझाव दूंगा। लेकिन अगर आप एक ऐसी विधि चाहते हैं जिसके लिए संदर्भ गिनती आदि की आवश्यकता नहीं है, तो आप इसे इस तरह से कर सकते हैं ...

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