2009-09-03 9 views
5

बस एक वैचारिक सवाल जिसे मैं चला रहा हूं। मेरे वर्तमान प्रोजेक्ट में ऐसा लगता है कि मैं बूस्ट smart_ptr और ptr_container लाइब्रेरीज़ का उपयोग कर रहा हूं। मैं कई अलग-अलग ऑब्जेक्ट्स में boost::ptr_vectors बना रहा था और कुछ पॉइंटर्स को boost::ptr_vector से दूसरे स्थानांतरित करने के लिए स्थानांतरण() विधि को कॉल कर रहा था।को बढ़ावा देना चाहिए :: ptr_vector जगह std :: vector में हर समय इस्तेमाल किया जाना चाहिए?

यह मेरी समझ है कि स्पष्ट रूप से ढेर आवंटित वस्तुओं के स्वामित्व को दिखाने के लिए महत्वपूर्ण है।

मेरा सवाल यह है कि, किसी ऑब्जेक्ट से संबंधित ढेर-आवंटित सदस्यों को बनाने के लिए इन बूस्ट लाइब्रेरीज़ का उपयोग करना वांछनीय होगा, लेकिन किसी भी प्रोसेसिंग करते समय get() के माध्यम से इन सदस्यों को सामान्य पॉइंटर्स का उपयोग करें।

उदाहरण के लिए ... एक गेम में टाइल्स का संग्रह हो सकता है जो इसके हैं। इन टाइल्स को boost::ptr_vector में बनाने का अर्थ हो सकता है। जब इन टाइलों पर खेल खत्म हो जाता है तो स्वचालित रूप से मुक्त हो जाना चाहिए।

लेकिन अगर मैं अस्थायी रूप से एक बैग वस्तु में इन टाइलें रखना चाहते हैं, मैं बैग में एक और boost::ptr_vector बना सकते हैं और transfer() या के माध्यम से बैग के लिए खेल का टाइलें हस्तांतरण मैं एक std::vector<Tile*> जहां टाइलें * के संदर्भ बनाना चाहिए चाहिए गेम में टाइल्स और बैग को पास करते हैं?

धन्यवाद।

** संपादित करें मुझे यह इंगित करना चाहिए कि मेरे उदाहरण में गेम में एक सदस्य के रूप में एक बैग वस्तु होगी। बैग केवल खेल के टाइल्स से भरेगा। तो बैग खेल के बिना मौजूद नहीं होगा।

+2

आपकी ऑब्जेक्ट्स पहली जगह में ढेर क्यों आवंटित हैं? यही वह जगह है जहां पहली अलार्म घंटी मेरे लिए बंद हो जाती है। 'ptr_vector' * दुर्लभ * मामलों में एक अच्छा समाधान है जब आपको वास्तव में ढेर-आवंटित वस्तुओं को पॉइंटर्स स्टोर करने की आवश्यकता होती है। लेकिन अगर वे मामले दुर्लभ नहीं हैं, तो आप इसे गलत कर रहे हैं। ;) यदि गेम में टाइल्स का संग्रह है, तो वेक्टर में * उन्हें * रखें। इसमें पॉइंटर्स मत डालें। – jalf

+1

यदि आपके पास C++ 11 कार्यान्वयन है तो इस प्रश्न का उत्तर काफी अप्रचलित है। उदाहरण के लिए, सी ++ 11 में ptr_x कक्षाओं के लिए बिल्कुल कोई कारण नहीं है। मानक कंटेनरों को केवल अपनी सामग्री को चलने योग्य होने की आवश्यकता होती है, जिसका अर्थ है ':: std :: unique_ptr' के कंटेनर इस के लिए जाने का तरीका हैं। – Omnifarious

+0

@jalf मैं उलझन में हूँ। तो अगर मुझे एक जटिल वस्तु (एक फ़ाइल से कहें) के वेक्टर को पॉप्युलेट करना है, तो मुझे हमेशा ढेर पर आवंटित नहीं करना चाहिए? अगर मैं इसे ढेर में आवंटित नहीं करता हूं, तो वस्तु को प्रतिलिपि बनाई जानी चाहिए और पूरी वस्तु को वेक्टर में कॉपी किया जाएगा। इसलिए यदि मैं इसे सही तरीके से पालन करता हूं, तो आमतौर पर एक साझा_प्टर का उपयोग करने की तुलना में कॉपी की लागत लगाना बेहतर होता है, है ना? और आमतौर पर आप केवल ptr_container का उपयोग करना चाहते हैं यदि ऑब्जेक्ट गैर-प्रतिलिपि योग्य है? – Jerahmeel

उत्तर

15

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

आप संकेत की एक अस्थायी वेक्टर बनाते हैं बस कुछ अन्य कार्य करने के लिए इसे पारित करने, और मूल ptr_vector अब भी उन सभी वस्तुओं का संदर्भ है, वहाँ कोई स्वामित्व हस्तांतरण है, और इसलिए आप अस्थायी वस्तु के लिए सादे vector का उपयोग करना चाहिए - बस के रूप में आप ptr_vector से एक ऑब्जेक्ट को पॉइंटर लेते हुए एक ऑब्जेक्ट को पास करने के लिए कच्चे सूचक का उपयोग करेंगे, लेकिन इसे कहीं भी स्टोर नहीं करते हैं।

1

boost::ptr_vector केवल पॉइंटर्स के वैक्टरों का उपयोग करने के अर्थशास्त्र में सुधार करने के लिए कार्य करता है। यदि, आपके उदाहरण में, मूल सरणी को नष्ट किया जा सकता है जबकि वैक्टरों का अस्थायी सेट उपयोग में है, तो आपको निश्चित रूप से उपयोग में रहते हुए हटाए जाने से रोकने के लिए shared_ptr एस के वेक्टर का उपयोग करना चाहिए। यदि नहीं, तो पॉइंटर्स का एक सादा पुराना वेक्टर उपयुक्त हो सकता है। चाहे आप std::vector या boost::ptr_vector चुनते हैं, वास्तव में कोई फर्क नहीं पड़ता कि वेक्टर दिखने वाले कोड को कितना अच्छा लगा।

4

मेरे अनुभव में, तीन मुख्य स्वामित्व पैटर्न हैं जो फसल हो जाते हैं। मैं उन्हें पेड़, डीएजी और ग्राफ कहूंगा।

सबसे आम पेड़ है। माता-पिता अपने बच्चों का मालिक है, जो बदले में अपने बच्चों का मालिक है। auto_ptr, scoped_ptr, नंगे पॉइंटर्स और बूस्ट ptr_x कक्षाएं जो आप आमतौर पर यहां देखते हैं। मेरी राय में, नंगे पॉइंटर्स को आम तौर पर टालना चाहिए क्योंकि वे कोई स्वामित्व अर्थशास्त्र नहीं देते हैं।

दूसरा सबसे आम डीएजी है। इसका मतलब है कि आप स्वामित्व साझा कर सकते हैं। माता-पिता के माता-पिता के बच्चे भी माता-पिता के अन्य बच्चों के बच्चे हो सकते हैं। TR1 और boost shared_ptr टेम्पलेट यहां मुख्य अभिनेता है। संदर्भ गणना एक व्यवहार्य रणनीति है जब आपके पास कोई चक्र नहीं होता है।

तीसरा सबसे आम पूर्ण ग्राफ है। इसका मतलब है कि आप चक्र हो सकते हैं। उन चक्रों को तोड़ने और त्रुटि के कुछ संभावित स्रोतों की लागत पर डीएजी पर लौटने के लिए कुछ रणनीतियां हैं। इन्हें आम तौर पर टीआर 1 या बूस्ट के कमजोर_प्टर टेम्पलेट द्वारा दर्शाया जाता है।

कम ग्राफ जिसे कमजोर_प्टर का उपयोग करके डीएजी में विभाजित नहीं किया जा सकता है वह समस्या है जिसे सी ++ में आसानी से हल नहीं किया जा सकता है। केवल अच्छे हैंडलर कचरा संग्रहण योजनाएं हैं। वे भी सबसे सामान्य हैं, जो कि अन्य दो योजनाओं को अच्छी तरह से संभालने में सक्षम हैं। लेकिन उनकी सामान्यता लागत पर आती है।

मेरी राय में, आप ptr_x कंटेनर कक्षाओं या auto_ptr का उपयोग नहीं कर सकते हैं जब तक कि आपको वास्तव में पॉइंटर्स के कंटेनर के बजाय ऑब्जेक्ट्स के कंटेनरों का उपयोग नहीं करना चाहिए। shared_ptr का उपयोग किया जा सकता है। सावधानी से सोचें कि आपको वास्तव में एक डीएजी की आवश्यकता है या नहीं।

बेशक मुझे लगता है कि लोगों को बूस्ट ptr_x कक्षाओं के बजाय scope_ptrs के कंटेनर का उपयोग करना चाहिए, लेकिन इसे सी ++ 0x के लिए इंतजार करना होगा। :-(

1

अपने खेल टाइल्स उदाहरण में, मेरी पहली वृत्ति बिल्कुल स्वामित्व के बारे में चिंता किए बिना एक vector<Tile>, नहीं एक vector<Tile*> या एक ptr_vector। फिर संकेत दिए गए टाइल करने के लिए आप के रूप में कृपया, का उपयोग बनाने के लिए हो सकता है, कि प्रदान की ऑब्जेक्ट्स जो पॉइंटर्स धारण करते हैं, वे टाइल्स के वेक्टर से बाहर नहीं निकलते हैं। आपने कहा है कि गेम समाप्त होने पर ही इसे नष्ट कर दिया जाता है, इसलिए यह मुश्किल नहीं होना चाहिए।

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

int main() { 
    vector<Tile*> v; 
    // fill in v, perhaps with heap objects, perhaps with stack objects. 
    runGame(v); 
} 

void runGame(const vector<Tile*> &v) { 
    Tile *firsttile = v[0]; 
    vector<Tile*> eventiles; 
    eventiles.push_back(v[2]); 
    eventiles.push_back(v[4]); 
    // and so on. No need to worry about ownership, 
    // just as long as I don't keep any pointers beyond return. 
    // It's my caller's problem to track and free heap objects, if any. 
} 
0

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

लेकिन बेहतर राय स्वामित्व के साथ गड़बड़ नहीं होगी, क्योंकि मुझे नहीं लगता कि इस विशेष मामले में इसकी आवश्यकता क्यों है। अगर दृश्य के पीछे कुछ है, तो अपनी पसंद बनाएं।

2

सबसे अधिक संभावना, समाधान आप देख रहे हैं नहीं संकेत दिए गए समय के सबसे अधिक के लिए की जरूरत नहीं है

std::vector<Tile> 

है। वेक्टर पहले से ही निहित वस्तुओं की स्मृति प्रबंधन का ख्याल रखता है। टाइल्स खेल के स्वामित्व में हैं, है ना? स्पष्ट करने का तरीका ऑब्जेक्ट्स को गेम क्लास में रखना है - केवल एक ही मामले जहां आपको आम तौर पर पॉइंटर्स की आवश्यकता होती है और गतिशील रूप से आवंटित व्यक्तिगत ऑब्जेक्ट्स होता है यदि आपको 1) पॉलिमॉर्फिज्म, या 2) साझा स्वामित्व की आवश्यकता होती है।

लेकिन पॉइंटर्स अपवाद होना चाहिए, नियम नहीं।

1

यदि गेम टाइल्स का मालिक है तो गेम डिलीशन के लिए responcable है।

ऐसा लगता है कि बैग वास्तव में वस्तुओं का स्वामित्व नहीं रखता है, इसलिए उन्हें हटाने के लिए इसे उत्तरदायी नहीं होना चाहिए। इस प्रकार मैं गेम ऑब्जेक्ट के भीतर ptr_vector का उपयोग करूंगा। लेकिन बैग में एक std :: वेक्टर का उपयोग करें।

नोट: मैं कभी भी किसी बैग को बैग से टाइल पर पॉइंटर पुनर्प्राप्त करने का उपयोग नहीं करूंगा। उन्हें केवल बैग से टाइल को रेफरेंसेटो पुनर्प्राप्त करने में सक्षम होना चाहिए।

0

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

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