Std :: make_unique और std :: unique_ptr के बीच अंतर


130

क्या std::make_uniqueकोई दक्षता लाभ है std::make_shared?

मैन्युअल रूप से निर्माण की तुलना में std::unique_ptr:

std::make_unique<int>(1);         // vs
std::unique_ptr<int>(new int(1));

क्या make_sharedकेवल लंबे हाथ कोड लिखने पर कोई दक्षता है?
एड हील

9
@ ईडील यह हो सकता है, क्योंकि make_sharedऑब्जेक्ट के लिए स्पेस और कंट्रोल ब्लॉक के लिए एक ही आवंटन में एक साथ जगह आवंटित कर सकते हैं। इसकी लागत यह है कि वस्तु को नियंत्रण खंड से अलग नहीं किया जा सकता है, इसलिए यदि आप weak_ptrबहुत अधिक उपयोग करते हैं तो आप अधिक मेमोरी का उपयोग करके समाप्त हो सकते हैं।
bames53

शायद यह एक अच्छा प्रारंभिक बिंदु है stackoverflow.com/questions/9302296/…
एड हील

जवाबों:


140

पीछे प्रेरणा make_uniqueमुख्य रूप से दो गुना है:

  • make_uniqueटेंपरेरी बनाने के लिए सुरक्षित है, जबकि स्पष्ट उपयोग के साथ newआपको अनाम टेम्परेरी का उपयोग नहीं करने के बारे में नियम को याद रखना होगा।

    foo(make_unique<T>(), make_unique<U>()); // exception safe
    
    foo(unique_ptr<T>(new T()), unique_ptr<U>(new U())); // unsafe*
  • के अलावा make_uniqueअंत में मतलब है कि हम 'कभी नहीं' उपयोग करने के लिए लोगों को बता सकते new" 'कभी नहीं' उपयोग करने के लिए पिछले शासन के बजाय newछोड़कर जब आप एक बनाने के unique_ptr"।

इसका तीसरा कारण भी है:

  • make_uniqueअनावश्यक प्रकार के उपयोग की आवश्यकता नहीं है। unique_ptr<T>(new T())->make_unique<T>()

कारणों में से कोई भी रनटाइम दक्षता में सुधार का उपयोग make_sharedनहीं करता है (संभावित रूप से उच्च शिखर मेमोरी उपयोग की कीमत पर, एक दूसरे आवंटन से बचने के कारण)।

* यह उम्मीद की जाती है कि C ++ 17 में एक नियम परिवर्तन शामिल होगा जिसका अर्थ है कि यह अब असुरक्षित नहीं है। C ++ समिति के पेपर P0400R0 और P0145R3 देखें


यह कहने के लिए अधिक समझ में आता है std::unique_ptrऔर std::shared_ptrइसलिए हम लोगों को "कभी उपयोग न करने" के लिए कह सकते हैं new
तीमुथियुस

2
@TimothyShields हाँ, यही मेरा मतलब है। यह सिर्फ इतना है कि सी ++ 11 में हमारे पास है make_sharedऔर make_uniqueअंतिम टुकड़ा जो पहले गायब था।
bames53

1
किसी भी तरह से आप संक्षेप में उल्लेख कर सकते हैं, या लिंक कर सकते हैं, अनाम अस्थायी उपयोग न करने का कारण?
डैन निसेनबाम

14
वास्तव में, से stackoverflow.com/a/19472607/368896 , मैं यह ... है कि इसका जवाब से, पर विचार निम्नलिखित समारोह कॉल मिल गया है f: f(unique_ptr<T>(new T), function_that_can_throw());-: इस सवाल का जवाब उद्धृत करने के लिए (क्रम में) संकलक कॉल करने के लिए अनुमति दी है: new T, function_that_can_throw(), unique_ptr<T>(...)। जाहिर है अगर function_that_can_throwवास्तव में फेंकता है तो आप लीक करते हैं। make_uniqueइस मामले को रोकता है। तो, मेरे सवाल का जवाब है।
डैन निसेनबाम

3
एक कारण मुझे एक बार std :: unique_ptr <T> (new T ()) का उपयोग करना पड़ा क्योंकि T का निर्माता निजी था। यहां तक ​​कि अगर std :: make_unique का कॉल क्लास T की एक सार्वजनिक फैक्ट्री विधि में था, तो यह संकलित नहीं किया गया क्योंकि एसटीडी के अंतर्निहित तरीकों में से एक :: make_unique निजी कंस्ट्रक्टर तक पहुंच नहीं सकता था। मैं उस विधि को दोस्त नहीं बनाना चाहता था क्योंकि मैं std के कार्यान्वयन पर भरोसा नहीं करना चाहता था :: make_unique। तो एकमात्र समाधान यह था, कक्षा टी के मेरे कारखाने के तरीके में नया, और फिर इसे एक std :: unique_ptr <T> में लपेटो।
पैट्रिक

14

std::make_uniqueऔर std::make_sharedइसके दो कारण हैं:

  1. ताकि आपको टेम्पलेट प्रकार के तर्कों को स्पष्ट रूप से सूचीबद्ध न करना पड़े।
  2. अतिरिक्त अपवाद सुरक्षा का उपयोग कर std::unique_ptrया std::shared_ptrरचनाकारों पर। ( यहां नोट्स अनुभाग देखें )

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


वे अपवाद-सुरक्षा के लिए भी हैं।
0x499602D2

@ 0x499602D2 और वह, अच्छा जोड़। यह पेज उसी के बारे में बात करता है।
तीमुथियुस

भविष्य के पाठकों के लिए, C ++ 17 फ़ंक्शन तर्कों की इंटरलाकिंग के लिए अनुमति नहीं देता है, इसलिए अपवाद-सुरक्षा के लिए तर्क अब आयोजित नहीं करता है। दो समानांतर के लिए स्मृति आवंटन std::make_sharedयह सुनिश्चित करेगा कि उनमें से कम से कम एक स्मार्ट मेमोरी पॉटर में लपेटे जाने से पहले अन्य मेमोरी आवंटन होता है, इसलिए कोई लीक नहीं है।
मैथबनी

7

एक कारण है कि आपको इसके बजाय std::unique_ptr(new A())या std::shared_ptr(new A())सीधे उपयोग करना होगा , वर्तमान दायरे से बाहर std::make_*()वर्ग के कंस्ट्रक्टर तक पहुंचने में असमर्थ है A


0

फ़ंक्शन कॉल पर विचार करें

void function(std::unique_ptr<A>(new A()), std::unique_ptr<B>(new B())) { ... }

मान लीजिए कि नया A()सफल होता है, लेकिन नया B()एक अपवाद फेंकता है: आप इसे अपने कार्यक्रम के सामान्य निष्पादन को फिर से शुरू करने के लिए पकड़ते हैं। दुर्भाग्य से, C ++ मानक को उस ऑब्जेक्ट A को नष्ट करने की आवश्यकता नहीं है और इसकी मेमोरी डीलॉलेटेड है: मेमोरी चुपचाप लीक हो जाती है और इसे साफ करने का कोई तरीका नहीं है। A और B को लपेटने से std::make_uniquesआपको यकीन है कि रिसाव नहीं होगा:

void function(std::make_unique<A>(), std::make_unique<B>()) { ... }

यहां मुद्दा यह है कि है std::make_unique<A>और std::make_unique<B>उनके विनाशकर्ता ट्रिगर किया जाएगा और स्मृति को मुक्त कर दिया: अब अस्थायी वस्तुओं रहे हैं, और अस्थायी वस्तुओं की सफाई सही ढंग से सी में निर्दिष्ट किया जाता ++ मानक। इसलिए यदि आप कर सकते हैं, तो हमेशा उपयोग की जाने वाली वस्तुओं को आवंटित करना पसंद करते हैं std::make_uniqueऔर std::make_shared

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