2008-10-18 12 views
8

मान लीजिए कि मेरे पास एक कक्षा है जहां मैं चाहता हूं कि उपयोगकर्ता मेरे सदस्यों में से एक का संदर्भ ले सके। कौन सा पसंद किया जाता है?सी ++ संदर्भ या कमजोर_पीआरआर वापस करने के लिए बेहतर है?

class Member; 

class ClassWithWeakPtr 
{ 
private: 
    boost::shared_ptr<Member> _member; 
public: 
    boost::weak_ptr<Member> GetMember(); 
}; 

या

class Member; 

class ClassWithCppReference 
{ 
private: 
    Member _member; 
public: 
    Member& GetMember() {return _member;} 
}; 

आप क्या सोचते हैं? एक दूसरे से बेहतर कब होता है?

उत्तर

0

मेरे बुनियादी, अज्ञानी दिशानिर्देश:

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

12

shared_ptr<> क्यों नहीं लौटाएं? वैसे भी क्लाइंट का उपयोग तब तक किया जाता है जब तक उसे इसकी आवश्यकता होती है, लेकिन 'सर्वर' वर्ग दूर होने पर कोई समस्या नहीं है।

ऐसी कई स्थितियां नहीं हैं जहां weak_ptr<> के अर्थशास्त्र बहुत अधिक समझ (कैश और ???) बनाते हैं। आम तौर पर जब कोई ग्राहक कुछ मांगता है, तो वह ग्राहक द्वारा निर्धारित उस चीज़ का स्वामित्व रखना चाहता है (और साझा स्वामित्व पूर्ण स्वामित्व के समान ही है)।

आप एक स्थिति है जहाँ 'सर्वर' वस्तु ग्राहक की जानकारी के बिना नष्ट किया जा सकता है (एक स्थिति है जहाँ आप use weak_ptr<> या shared_ptr<> करना चाह सकते हैं) सबसे बुरी बात आप कर सकते हैं के बारे में है, तो एक सदस्य के लिए एक संदर्भ वापसी है। इस मामले में, ग्राहक यह नहीं जान सकता कि लौटा संदर्भ तक पहुंच सुरक्षित है या नहीं। आपको सदस्य की एक प्रति या एक स्मार्ट सूचक वापस करना होगा जो सदस्य के जीवनकाल को सही तरीके से प्रबंधित कर सकता है।

याद रखें कि ऐसी स्थिति में जहां एक अभिव्यक्ति है जो अस्थायी ClassWithCppReference (जो हमेशा स्पष्ट नहीं होती) उत्पन्न करती है, क्लाइंट जो GetMember() पर कॉल करता है, वह अगले कथन में लौटा संदर्भ भी उपयोग नहीं कर पाएगा।

4

आपको अपने आंतरिक को दूर करने से बचना चाहिए; यह दिशानिर्देश एन है। "सी ++ कोडिंग मानकों" के 42 (हर्ब सटर और आंद्रेई अलेक्जेंड्रेसकू)। यदि आपको कुछ कारणों से कॉन्स्ट संदर्भ वापस करने के लिए बेहतर है, तो कोई सूचक नहीं है क्योंकि स्थिरता इसके माध्यम से प्रचार नहीं करता है।

weak_ptr <> एक व्यावहारिक समाधान प्रतीत होता है भले ही इसका मूल उद्देश्य share_ptr के चक्रों से बचें। इसके बजाय यदि आप एक साझा_ptr < वापस करते हैं> आप इस तरह के आंतरिक जीवन का विस्तार करते हैं जो ज्यादातर मामलों में समझ में नहीं आता है।

किसी घटना के साथ समस्या जो दूर हो जाती है, जबकि कोई व्यक्ति अपने आंतरिक संदर्भों को संदर्भित करता है, उसे थ्रेड के बीच सही सिंक्रनाइज़ेशन/संचार का सामना करना पड़ता है।

+0

सिंक्रनाइज़ेशन एक संदर्भ लौटने के साथ समस्या को ठीक से ठीक नहीं करता है। यदि GetMember() को अस्थायी पर कॉल किया जाता है, तो संदर्भ लगभग तुरंत अमान्य हो जाएगा। –

+0

मैं आपसे सहमत हूं। पोस्टिंग करते समय मैं आलसी था, और कॉन्स्ट-नेस नहीं जोड़ा। –

2

मुझे लगता है कि एकमात्र उचित उत्तर है, यह इस बात पर निर्भर करता है कि सदस्य कक्षा से कैसे संबंधित है, और आप क्लास के उपयोगकर्ताओं को क्या करना चाहते हैं। क्या _member एक सार्थक अस्तित्व है जो कक्षा वस्तु से स्वतंत्र है? यदि ऐसा नहीं होता है, तो मुझे लगता है कि shared_ptr का उपयोग करने के लिए मुझे कोई समझ नहीं आती है, चाहे आप weak_ptr या shared_ptr लौटाएं। अनिवार्य रूप से या तो उपयोगकर्ता को उस सदस्य ऑब्जेक्ट तक पहुंच प्रदान की जाएगी जो क्लास ऑब्जेक्ट को पार कर सकती है जो इसका अर्थ देती है। यह एक दुर्घटना को रोक सकता है, लेकिन एक गंभीर डिजाइन त्रुटि छिपाने की लागत पर।

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

4

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

मैं प्रोग्राम हैं जो defensive copying की एक बहुत कुछ कर लिखा है। यह जावा में एक मुहावरे है, जहां, क्योंकि सभी ऑब्जेक्ट पॉइंटर द्वारा पारित किए जाते हैं, वहां बहुत सारे एलियासिंग चल रहे हैं, इसलिए आप अलियासिंग को तोड़ने के लिए अपनी कक्षा में आने/बाहर जाने वाली कुछ भी कॉपी करते हैं, यह सुनिश्चित करना कि आपकी कक्षा के क्लाइंट आपके क्लास इनवेरिएंट का उल्लंघन नहीं कर सकते तथ्य के बाद एक वस्तु को संशोधित करके।

कार्यक्रमों मैं लिखा है रक्षा स्थानों में पूरे ढांचे, पूरे सूचियों और नक्शे सहित नकल की है। यह सुनिश्चित करने के लिए कि प्रदर्शन प्रभावित नहीं हुआ है, मैंने कार्यक्रम को बड़े पैमाने पर प्रोफाइल किया। मुख्य बाधाएं कहीं और थीं (और फिर भी, मैंने उन अन्य स्थानों को ट्यून किया ताकि मुख्य बाधा नेटवर्क हो)। कार्यक्रम के गर्म स्थानों में इस रक्षात्मक प्रतिलिपि को कहीं भी नहीं मिला।


ईटीए: मैं, मेरा संदेश की बात को स्पष्ट करने के बाद से एक टिप्पणीकार यह मैं कैसे इरादा से अलग ढंग से पढ़ा जरूरत महसूस, और बहुत संभव है दूसरों भी किया है। मेरा मुद्दा यह नहीं है कि चारों ओर सामान की प्रतिलिपि बनाना ठीक है; बल्कि, किसी को हमेशा अपने कोड के प्रदर्शन को प्रोफ़ाइल करना चाहिए, बजाय यह अनुमान लगाएगा कि यह कैसा प्रदर्शन करेगा।

कभी-कभी, जब संपूर्ण संरचनाओं की प्रतिलिपि बनाते हैं तो भी स्वीकार्य प्रदर्शन मिलता है, और साथ ही कोड को लिखना आसान बनाता है, फिर मेरी राय में, यह कोड की तुलना में बेहतर व्यापार (ज्यादातर मामलों में) है जो केवल मामूली तेज़ है लेकिन बहुत कुछ अधिक जटिल।

+1

क्या आप अपने प्रोफाइल पर कुछ अक्षमता में व्यवस्थित रूप से बेकिंग कर रहे हैं, तो क्या आप एक प्रोफाइलर के साथ सटीक रूप से बता सकते हैं? यदि आपके कोड में सब कुछ धीमा हो जाता है, तो प्रोफाइलर को कोई चीज़ नहीं दिखाई देगी, लेकिन आपका प्रोग्राम अभी भी धीमा हो जाएगा। – Sol

+0

(बेशक, यदि आप ऐसी स्थिति में हैं जहां दो वर्गों को डीकॉप्लिंग करना महत्वपूर्ण है, तो गैर-कॉन्स्ट संदर्भ के बजाय प्रतियों का उपयोग करना बहुत ही उचित है!) – Sol

+0

आई/ओ जैसे संसाधन अप्रभावित हैं, इसलिए हाँ, प्रोफाइलर अभी भी पाएगा आपके गर्म धब्बे, जब तक कि सभी संसाधन बाधाएं नहीं चली जातीं। रैम बाध्य नहीं हैं कई अनुप्रयोगों। –

-1

संदर्भ के आधार पर, या तो एक ठीक हो सकता है। किसी सदस्य को 'लाइव' लिंक लौटने के साथ मुख्य समस्या (यदि आपको पहले स्थान पर किसी को बेनकाब करना है) यह है कि जो कोई भी खुलासा सदस्य का उपयोग करता है वह यह है कि आपका ग्राहक उस ऑब्जेक्ट की मौजूदगी से अधिक समय तक हो सकता है। और यदि आपका ग्राहक किसी संदर्भ के माध्यम से उस सदस्य को एक्सेस करता है, जिसमें इसकी ऑब्जेक्ट गुंजाइश से बाहर हो जाती है, तो आपको 'अजीब' दुर्घटनाओं, गलत मूल्यों और समान मज़े का सामना करना पड़ेगा। सिफारिश नहीं की गई।

weak_ptr <> रिटर्निंग प्रमुख लाभ यह है कि ग्राहक उस वस्तु उनके पास पहुंच कोशिश कर रहे हैं चला गया है, जो संदर्भ नहीं कर सकते करने के लिए संवाद करने में सक्षम हो जाएगा है।

मेरे 2 पैसे के मूल्य होगा:

  • अपने ग्राहकों में से कोई भी कभी भी सदस्य का प्रयोग करेंगे, तो आप लेखक के रूप में यह का इस्तेमाल करते हैं और वस्तु जीवन काल को नियंत्रित करने के केवल एक ही व्यक्ति, एक लौट रहे हैं संदर्भ ठीक है। कॉन्स्ट संदर्भ भी बेहतर होगा लेकिन वास्तविक कोड में मौजूदा कोड के साथ यह हमेशा संभव नहीं है।
  • किसी और का उपयोग और सदस्य का प्रयोग करेंगे, खासकर यदि आप एक पुस्तकालय लिख रहे हैं, weak_ptr < वापस लौटाते हैं>।यह आपको बहुत दुख बचाएगा और डीबगिंग को आसान बना देगा।
  • मैं एक साझा_ptr <> वापस नहीं लौटाऊंगा। मैंने इस दृष्टिकोण को देखा है और आमतौर पर उन लोगों द्वारा पसंद किया जाता है जो कमजोर_पीआरआर/कमजोर संदर्भ की अवधारणा से असहज हैं। इसके साथ मैं मुख्य नकारात्मक पक्ष यह देखता हूं कि यह कृत्रिम रूप से किसी अन्य वस्तु के सदस्य के जीवनकाल को अपनी वस्तु के दायरे से आगे बढ़ाएगा। 99% मामलों में यह अवधारणात्मक रूप से गलत है और इससे भी बदतर, आपकी प्रोग्रामिंग त्रुटि (किसी और चीज को एक्सेस करना) को एक वैचारिक त्रुटि में बदल सकता है (को कोई और नहीं होना चाहिए)।
+0

एरर ... क्या आप एक shared_ptr को कमजोर_प्टर को बढ़ावा नहीं दे सकते? इसलिए जब तक आप मूल shared_ptr दूर जाने से पहले इसे प्राप्त करते हैं, तब तक आप कृत्रिम रूप से किसी अन्य ऑब्जेक्ट के सदस्य का जीवनकाल बढ़ा सकते हैं, भले ही वह सदस्य कमजोर_पीआरआर के साथ वापस आ गया हो। – Sol

+0

हां, आप कर सकते हैं (आपको वास्तव में ऑब्जेक्ट का उपयोग करने के लिए करना है) और हां, आप सही हैं कि आप इसका उपयोग ऑब्जेक्ट के जीवनकाल को बढ़ा सकते हैं। यह सिर्फ आपको पैर में गलती से शूट करने के लिए थोड़ा कठिन बनाता है लेकिन यह आपको इरादे से नहीं बचाता है ... –

+1

तो weak_ptr के साथ संदर्भ के दायरे को "केवल" गलत तरीके से विस्तारित किया गया है जबकि उपयोगकर्ता ने weak_ptr को बढ़ावा दिया है shared_ptr। यदि ऑब्जेक्ट की अवधि को विस्तारित करना गलत है, तो इसे थोड़ा बढ़ाकर शायद गलत भी है, और अब आपके पास एक छोटे पदचिह्न के साथ एक बग है। यह बेहतर नहीं है ... –

1

एक कमजोर सूचक लौटने से निश्चित रूप से अधिक महंगा होगा और कोई वास्तविक उद्देश्य नहीं होगा - आप मुख्य वस्तु के जीवन से अधिक समय तक स्वामित्व पर नहीं लटका सकते हैं।

1

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

0

अधिकांश स्थितियों में, मैं प्रदान करेगा

const Member& GetMember() const; 
Member& GetMember(); // ideally, only if clients can modify it without 
        // breaking any invariants of the Class 

weak_ptr<Member> GetMemberWptr(); // only if there is a specific need 
            // for holding a weak pointer. 

इसके पीछे तर्क यह है कि (भी मेरे और शायद कई अन्य) एक विधि GetMember() का तात्पर्य है कि Classmember का मालिक है और इसलिए लौटे संदर्भ केवल हो जाएगा बुला है युक्त वस्तु के जीवनकाल के लिए मान्य है।

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

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

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