Unique_ptr <Derived> का अर्थ क्यों अनूठे_ptr <Base> से लिया जाता है?


21

मैंने निम्नलिखित कोड लिखा है जो कि unique_ptr<Derived>जहां unique_ptr<Base>अपेक्षित है वहां उपयोग करता है

class Base {
    int i;
 public:
    Base( int i ) : i(i) {}
    int getI() const { return i; }
};

class Derived : public Base {
    float f;
 public:
    Derived( int i, float f ) : Base(i), f(f) {}
    float getF() const { return f; }
};

void printBase( unique_ptr<Base> base )
{
    cout << "f: " << base->getI() << endl;
}

unique_ptr<Base> makeBase()
{
    return make_unique<Derived>( 2, 3.0f );
}

unique_ptr<Derived> makeDerived()
{
    return make_unique<Derived>( 2, 3.0f );
}

int main( int argc, char * argv [] )
{
    unique_ptr<Base> base1 = makeBase();
    unique_ptr<Base> base2 = makeDerived();
    printBase( make_unique<Derived>( 2, 3.0f ) );

    return 0;
}

और मुझे उम्मीद थी कि यह कोड संकलित नहीं होगा, क्योंकि मेरी समझ के अनुसार unique_ptr<Base>और unique_ptr<Derived>असंबंधित प्रकार हैं और unique_ptr<Derived>वास्तव में ऐसा नहीं है unique_ptr<Base>जिससे असाइनमेंट को काम नहीं करना चाहिए।

लेकिन यह काम करता है कुछ जादू के लिए धन्यवाद, और मुझे समझ में नहीं आता क्यों, या भले ही ऐसा करने के लिए सुरक्षित हो। कोई समझा सकता है कृपया?


3
स्मार्ट पॉइंटर्स समृद्ध करने के लिए हैं जो पॉइंटर्स इसे सीमित नहीं कर सकते हैं। यदि यह संभव नहीं unique_ptrहोता तो विरासत की मौजूदगी में बेकार हो जाता
idclev 463035818

3
"लेकिन यह काम करता है कुछ जादू के लिए धन्यवाद" । लगभग, आपको यूबी मिला है क्योंकि Baseवर्चुअल विध्वंसक नहीं है।
Jarod42

जवाबों:


25

आपके द्वारा खोजा जा रहा जादू का बिटकॉइन कंवर्टर # 6 यहां है :

template<class U, class E>
unique_ptr(unique_ptr<U, E> &&u) noexcept;

यह एक निष्कासन std::unique_ptr<T>से एक अंतर्निहित निर्माण को सक्षम बनाता है std::unique_ptr<U> यदि (स्पष्टता के लिए हटाए जाने पर चमकाने):

unique_ptr<U, E>::pointer स्पष्ट रूप से परिवर्तनीय है pointer

जो कहना है, यह निहित-से-आधार रूपांतरणों सहित निहित कच्चे सूचक रूपांतरणों की नकल करता है, और वह करता है जो आप ™ से सुरक्षित रूप से उम्मीद करते हैं (जीवनकाल के संदर्भ में - आपको अभी भी यह सुनिश्चित करने की आवश्यकता है कि आधार प्रकार को बहुरूपिक रूप से हटाया जा सकता है)।


2
AFAIK के Baseविध्वंसक को विध्वंसक नहीं कहेंगे Derived, इसलिए मुझे यकीन नहीं है कि क्या यह वास्तव में सुरक्षित है। (यह कच्चे सूचक से कम नहीं सुरक्षित, बेशक है।)
cpplearner

14

क्योंकि std::unique_ptrएक कंवर्टिंग कंस्ट्रक्टर है

template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;

तथा

यह निर्माता केवल ओवरलोड रिज़ॉल्यूशन में भाग लेता है यदि निम्न में से सभी सत्य है:

a) unique_ptr<U, E>::pointerअनुमानित रूप से परिवर्तनीय हैpointer

...

एक Derived*करने के लिए परिवर्तित कर सकते हैं Base*परोक्ष और फिर रूपांतरण से निर्माता इस मामले के लिए लागू किया जा सकता। फिर एक संकेत std::unique_ptr<Base>से परिवर्तित किया जा सकता है std::unique_ptr<Derived>जैसे कि कच्चा सूचक करता है। (ध्यान दें कि की विशेषता के कारण std::unique_ptr<Derived>निर्माण के लिए एक प्रतिद्वंद्विता होनी चाहिए ।)std::unique_ptr<Base>std::unique_ptr


7

आप कर सकते हैं परोक्ष एक का निर्माण std::unique_ptr<T>एक से उदाहरण rvalue की std::unique_ptr<S>जब भी Sकरने के लिए परिवर्तनीय है T। यह यहां कंस्ट्रक्टर # 6 के कारण है । इस मामले में स्वामित्व स्थानांतरित किया जाता है।

आपके उदाहरण में, आपके पास केवल प्रकार के अंतराल हैं std::uinque_ptr<Derived>(क्योंकि वापसी का मूल्य std::make_uniqueएक प्रतिद्वंद्विता है), और जब आप इसका उपयोग करते हैं std::unique_ptr<Base>, तो, जैसा कि ऊपर उल्लेख किया गया है, निर्माता का आह्वान किया गया है। std::unique_ptr<Derived>सवाल इसलिए केवल समय की एक छोटी राशि के लिए लाइव में वस्तुओं, यानी वे बनाई गई हैं, तो स्वामित्व के लिए पारित हो जाता है std::unique_ptr<Base>उद्देश्य यह है कि के बारे में अधिक प्रयोग किया जाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.