2012-01-03 6 views
47

मैंने एक स्थैतिक फैक्ट्री विधि लिखी है जो एक अन्य डेटा ऑब्जेक्ट से पॉप्युलेट की गई एक नई Foobar ऑब्जेक्ट देता है। मैंने हाल ही में स्वामित्व अर्थशास्त्र के साथ भ्रमित किया है और मुझे आश्चर्य है कि क्या मैं इस फैक्टरी विधि को unique_ptr लौटाकर सही संदेश भेज रहा हूं।स्वामित्व semantics जैसे कच्चे सूचक के लिए unique_ptr वापस करने के लिए बुरा अभ्यास?

class Foobar { 
public: 
    static unique_ptr<Foobar> factory(DataObject data); 
} 

मेरा इरादा ग्राहक कोड को बताना है कि वे सूचक हैं। एक स्मार्ट सूचक के बिना, मैं बस Foobar* वापस आऊंगा। हालांकि, मैं यह लागू करना चाहता हूं कि संभावित बग से बचने के लिए यह स्मृति हटा दी जाए, इसलिए unique_ptr उचित समाधान की तरह लग रहा था। यदि ग्राहक पॉइंटर के जीवनकाल को विस्तारित करना चाहता है, तो वे प्राप्त करने के बाद बस .release() पर कॉल करें।

Foobar* myFoo = Foobar::factory(data).release(); 

मेरा प्रश्न दो भागों में आता है:

  1. इस दृष्टिकोण सही स्वामित्व अर्थ विज्ञान व्यक्त करता है?
  2. क्या यह कच्चे सूचक के बजाय unique_ptr वापस करने के लिए "खराब अभ्यास" है?
+0

आप एक unqiue_ptr ग्राहक बताने के लिए वे सूचक ही वापस लौट रहे हैं: तो मैं कुछ इस तरह करना होगा? यह वही विपरीत है जो मैं अपेक्षा करता हूं (क्योंकि उन्हें स्पष्ट रूप से अद्वितीय सूचक का स्वामित्व लेना होगा)। – jknupp

+1

इसके बजाय आप move-semantics का उपयोग करना चाहेंगे (यदि आप C++ 11 का उपयोग करने में सक्षम हैं)। इसके साथ, यह तय करने के लिए उपयोगकर्ता पर निर्भर करता है कि फैक्ट्री द्वारा बनाई गई वस्तु के जीवनकाल को कैसे बढ़ाया जाए। – evnu

+1

@evnu ऐसा कुछ है जो आपके लिए स्वचालित रूप से किया जाता है, नहीं? –

उत्तर

58

फैक्टरी विधि से std::unique_ptr लौटाना ठीक है और एक अनुशंसित अभ्यास होना चाहिए। संदेश जो यह बताता है वह है (आईएमओ): अब आप इस ऑब्जेक्ट का एकमात्र मालिक हैं। इसके अलावा, आपकी सुविधा के लिए, वस्तु जानता है कि खुद को कैसे नष्ट करें।

मुझे लगता है कि यह कच्चे सूचक को लौटने के बाद बेहतर है (जहां ग्राहक को यह याद रखना होगा कि इस सूचक का निपटान कैसे और कैसे किया जाए)।

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

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

std::unique_ptr<FooBar> myFoo = Foobar::factory(data); 
//or: 
std::shared_ptr<FooBar> myFoo = Foobar::factory(data); 

व्यक्तिगत तौर पर मैं भी लौट आए सूचक प्रकार के लिए एक typedef जोड़ना होगा (इस मामले std::unique_ptr<Foobar> में) और या इस्तेमाल Deleter (इस मामले एसटीडी में :: default_deleter) करने के लिए आपका कारखाना वस्तु इससे आप इसे आसान बनाते हैं यदि आप बाद में अपने पॉइंटर के आवंटन को बदलने का निर्णय लेते हैं (और इसलिए पॉइंटर के विनाश के लिए एक अलग विधि की आवश्यकता है, जो std::unique_ptr के दूसरे टेम्पलेट पैरामीटर के रूप में दिखाई देगा)।

class Foobar { 
public: 
    typedef std::default_deleter<Foobar>  deleter; 
    typedef std::unique_ptr<Foobar, deleter> unique_ptr; 

    static unique_ptr factory(DataObject data); 
} 

Foobar::unique_ptr myFoo = Foobar::factory(data); 
//or: 
std::shared_ptr<Foobar> myFoo = Foobar::factory(data); 
+3

मेरा मतलब 'रिलीज()' के बारे में मेरा मतलब नहीं है कि वह भ्रामक या भ्रमित हो, क्षमा करें। यह नया कोड काफी बड़े मौजूदा एप्लिकेशन (सी ++ की 1-2 मिलियन लाइनों) में जा रहा है जो किसी भी स्मार्ट पॉइंटर्स (COM के अलावा) का उपयोग नहीं करता है।अगर मुझे विरासत कोड प्रभावी ढंग से "आवश्यक" बनाता है तो कच्चे सूचक को पाने का कोई उचित तरीका नहीं है, तो मुझे पता है कि मेरी टीम पर अन्य लोग चिंतित होंगे। मैं निश्चित रूप से उचित चेतावनियां दूंगा और जब संभव हो तो unique_ptr/shared_ptr पर चिपकने की अनुशंसा करूंगा। मुझे वास्तव में आपके टाइपपीफ विचार पसंद हैं, जो जेम्स मैकनेलिस के अलावा आपका उत्तर सेट करता है। अंतर्दृष्टि के लिए धन्यवाद। –

17

std::unique_ptr विशिष्ट रूप से उस वस्तु का मालिक है जिस पर यह इंगित करता है। यह कहता है "मैं इस वस्तु का मालिक हूं, और कोई और नहीं करता है।"

यह वही है जो आप व्यक्त करने की कोशिश कर रहे हैं: आप कह रहे हैं "इस फ़ंक्शन का कॉलर: अब आप इस ऑब्जेक्ट का एकमात्र मालिक हैं; कृपया इसके साथ करें, इसका जीवनकाल आपकी ज़िम्मेदारी है।"

+0

दरअसल, लेकिन यह 'std :: shared_pointer <>' क्यों नहीं लौटा है? यह एक ही प्रभाव प्राप्त करता है लेकिन सूचक की कई प्रतियों की अनुमति देता है। –

+8

@ AndréCaron: यदि आप बस इतना करना चाहते हैं तो 'std :: shared_ptr' के उपयोग को लागू क्यों करें, कॉलर को स्वामित्व हस्तांतरण करना है? कॉलर को ऑब्जेक्ट का स्वामित्व 'std :: shared_ptr' पर देना चाहिए यदि वह (या किसी अन्य प्रकार का स्मार्ट पॉइंटर, यदि कॉलर चाहता है)। –

+7

@ एंड्रे कैरॉन: कारण मूल रूप से प्रदर्शन है। कारखाना यह नहीं जान सकता कि ग्राहक 'std :: shared_ptr' पर' std :: shared_ptr' पर कार्यक्षमता को जोड़ देगा या नहीं, तो कुछ कार्यक्षमता के लिए बलिदान प्रदर्शन क्यों करें, जो आवश्यक नहीं हो सकता है। चूंकि 'shared_ptr' का निर्माण किया जा सकता है और' unique_ptr' से असाइन किया गया है, वास्तव में कोई लाभ नहीं है – Grizzly

6

यह सही अर्थशास्त्र को बिल्कुल सही बताता है और जिस तरह से मुझे लगता है कि सी ++ में सभी कारखानों को काम करना चाहिए: std::unique_ptr<T> किसी भी तरह के स्वामित्व अर्थशास्त्र को लागू नहीं करता है और यह बेहद सस्ता है।

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