2012-01-14 26 views
7

मैं कम से [VC10 के] unique_ptr देख रहा हूँ और वे करते हैं कुछ चीज़ें मुझे समझ नहीं आता:मुझे remove_reference और add_reference का उपयोग कब करना चाहिए?

typedef typename tr1::remove_reference<_Dx>::type _Dx_noref; 

_Dx_noref& get_deleter() 
    { // return reference to deleter 
    return (_Mydel); 
    } 

unique_ptr(pointer _Ptr, 
    typename _If<tr1::is_reference<_Dx>::value, _Dx, 
     const typename tr1::remove_reference<_Dx>::type&>::_Type _Dt) 
    : _Mybase(_Ptr, _Dt) 
    { // construct with pointer and (maybe const) deleter& 
    } 

typename tr1::add_reference<_Ty>::type operator*() const 
    { // return reference to object 
    return (*this->_Myptr); 
    } 

बस लिख नहीं चाहेंगे _Dx & या _Ty & एक ही बात हो सकता है?

मैं वास्तव में समझते हैं कि वे क्यों इसे यहाँ हालांकि किया:

unique_ptr(pointer _Ptr, typename tr1::remove_reference<_Dx>::type&& _Dt) 
    : _Mybase(_Ptr, _STD move(_Dt)) 
    { // construct by moving deleter 
    } 
+5

उत्तर यह है कि आपको सी ++ सीखने की आवश्यकता है, और फिर आपको यह पता होना चाहिए कि सही चीज़ कैसे पूछें। मुझे खेद है कि अगर यह कठोर लगता है, लेकिन एक बार जब आप टेम्पलेट्स और तर्क कटौती पर दृढ़ समझ लेते हैं, तो आप इसे समझने में सक्षम होंगे। लेकिन गहरे छोर पर कूदने का कोई मतलब नहीं है, * खासकर * वास्तविक दुनिया पुस्तकालय कार्यान्वयन को देखकर। यह एक पाठ्यपुस्तक पढ़ने के बजाय फारस में कलाकृतियों को खोदकर प्राचीन ग्रीक सीखने की कोशिश की तरह है। –

+7

@ केरेकस्क: कभी-कभी पूरी पाठ्यपुस्तक की तुलना में एक अच्छी तरह से समझाया गया उदाहरण से सीखना बहुत आसान होता है। इसके अलावा, अधिकांश पाठ्यपुस्तक इस सामग्री को भी कवर नहीं करेंगे, क्योंकि वे भाषा में मौजूद रावल-संदर्भ लिखे गए थे। यह एक वैध और अच्छी तरह से पूछे जाने वाले प्रश्न है, कि मैं सी ++ सीख रहे बहुत से लोगों के लिए उपयोगी होने की कल्पना कर सकता हूं। – Mankarse

+1

@KerrekSB यह बिल्कुल ठीक नहीं है जिसे मैं देख सकता हूं। यहां तक ​​कि अगर मैंने इस नियम में ऐसा किया जो सीटीओ को ऐसा करने की ज़रूरत है, तो शायद मैं इसे किसी भी उदाहरण के बिना यहां जोड़ नहीं सकता। एक और नोट पर, क्या आप कृपया मेरी सभी पोस्टों को फ्लेम करना बंद कर सकते हैं? आपको स्पष्ट रूप से मेरे साथ समस्या है (मुझे परवाह नहीं है क्यों)। – David

उत्तर

14

get_deleter

कोई संदर्भ, वापसी प्रकार से निकाल दिया जाता है तो एक संदर्भ वापस जोड़ा गया है। संगत सी ++ 11 में, & को मौजूदा & (या &&) में & का उत्पादन करता है। हालांकि, सी ++ 03 में, यह संदर्भ प्रकार का संदर्भ बनायेगा, जो अवैध था। संभावित रूप से एमएसवीसी पुराने नियमों का उपयोग कर रहा है, या यह कोड तब लिखा गया था जब यह हुआ और बना रहता है क्योंकि यह हानिरहित है।

निर्माता

यहाँ वे संदर्भ निकालें, const जोड़ें और फिर संदर्भ वापस जोड़ने के लिए, const संदर्भ से गुज़र जाए। ऐसा इसलिए है क्योंकि const सीधे संदर्भ प्रकार में कुछ भी नहीं जोड़ता है! (§8.3.2/1) या तो सी ++ 11 या सी ++ 03 में, पैरामीटर घोषणा वैध होगी लेकिन const नहीं जोड़ती है, अगर संदर्भ हटाया नहीं गया था और प्रतिस्थापित किया गया था।

operator*

यह अनिवार्य रूप से get_deleter रूप में ही है, लेकिन वे एक अलग तरीके से इसके बारे में चला गया, और _Ty के साथ शुरू करने के लिए एक संदर्भ प्रकार नहीं हो सकता। मुझे लगता है कि _Ty& पर्याप्त होगा, लेकिन यह उनका विशेषाधिकार है।

+1

बहुत बढ़िया ब्रेकडाउन मैन - धन्यवाद। अगर मैं कर सकता था, तो मैं कई बार उभरा होता था, खासतौर पर दूसरों के बाद कोई स्पष्ट कारण नहीं था। संयोग से, क्यों शुरू करने के लिए संदर्भ प्रकार नहीं हो सकता है? – David

+0

@ डेव: ठीक है, '_Ty' * एक संदर्भ प्रकार नहीं होना चाहिए क्योंकि आपके पास किसी संदर्भ में सूचक नहीं हो सकता है। (8.3.2/5) मैं यह जांच नहीं कर रहा हूं कि क्या कुछ प्रश्नोत्तरी है जो उस मामले में संदर्भ को मददगार तरीके से स्ट्रिप करती है, लेकिन अन्यथा 'unique_ptr' के सदस्य typedef' सूचक 'का गठन खराब हो जाएगा। – Potatoswatter

+0

@ डेव: कोई भी आपको फ्लेम नहीं करता; रचनात्मक आलोचना होने का इरादा इतना खराब था कि वह मूर्खतापूर्ण है। – ildjarn

2

यहाँ के लिए कारण है कि हम remove_reference की जरूरत है, std::move के कार्यान्वयन में संभवतः ठेठ एक उदाहरण है,,: लक्ष्य एक rvalue-संदर्भ प्रकार, समारोह तर्क के निष्कर्ष निकाला प्रकार के आधार पर वापस जाने के लिए है।

उदाहरण: Foo x; move(x); यहां move(x) को Foo&& टाइप करना चाहिए। लेकिन move का तर्क Foo& प्रकार की अभिव्यक्ति है। तो move फ़ंक्शन सही प्रकार को कैसे घटा सकता है?

template <typename T> T && move(??? x) { return static_cast<T&&>(x); } 

लेकिन क्या ??? में जाने चाहिए:

पहला प्रयास साधारण टेम्पलेट तर्क कटौती का उपयोग करें और एक डाली उपयोग करने के लिए है? अगर हम T x कहते हैं, तो TFoo& के रूप में घटाया जाएगा; अगर हम T & x कहते हैं, तो T = Foo, और यदि हम T && x कहते हैं, तो यह बिल्कुल मेल नहीं खाएगा। दूसरा संस्करण, T & x, उपयोगी प्रतीत होता है।

लेकिन तब समारोह rvalues ​​पर काम नहीं करता के साथ शुरू (जैसे move(Foo(...))। इस मामले में, हम T && x चाहते इतनी के रूप में वांछित। हम दो भार के हो सकता है T = Foo और T&& = Foo&&, लेकिन कई भार के होने क्योंकि यह अवांछनीय है जटिलता बढ़ जाती है।और आखिरकार, अगर कोई टेम्पलेट paramete को move<Foo&>(x) के रूप में स्पष्ट रूप से निर्दिष्ट करना था, तो फ़ंक्शन कभी काम नहीं करेगा, क्योंकि T = Foo&, तब T&& = Foo& भी होगा।

तो में remove_reference आता है:

template <typename T> 
typename std::remove_reference<T>::type && move(T && x) 
{ 
    return static_cast<typename std::remove_reference<T>::type &&>(x); 
} 

पहले, नया संदर्भ गिर नियमों मतलब है कि या तो TFoo& या Foo&& दो मामलों में के रूप में deduces है। फिर, remove_reference संदर्भ स्ट्रिप्स करता है और किसी भी मामले में Foo टाइप करता है, और && वांछित Foo&& वापसी प्रकार बनाता है।

एक oversimplified सारांश में: हमें remove_reference की आवश्यकता है क्योंकि (Foo&)&&Foo& है और Foo&& नहीं है। यदि आप कभी भी टेम्पलेट कोड लिखते हैं जिसके लिए टेम्पलेट पैरामीटर के मूल प्रकार की आवश्यकता होती है जिसे U& या U&& के रूप में घटाया जा सकता है, तो आप इस मॉडल का उपयोग कर सकते हैं।

1

template class add_reference क्योंकि void type (void&) के संदर्भ अनुमति नहीं है void, const void और const volatile void के लिए विशेषज्ञता है। यदि _Ty& का उपयोग किया जाता है, तो _Ty = void पर संकलन त्रुटि उत्पन्न होगी।

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

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