एक सरणी में साझा किया गया: क्या इसका उपयोग किया जाना चाहिए?


172

बस के बारे में एक छोटी सी क्वेरी shared_ptr

shared_ptrकिसी व्यूह की ओर इशारा करते हुए उसका उपयोग करना अच्छा है ? उदाहरण के लिए,

shared_ptr<int> sp(new int[10]);

यदि नहीं, तो क्यों नहीं? एक कारण जो मुझे पहले से पता है वह है वेतन वृद्धि / वृद्धि नहीं shared_ptr। इसलिए यह एक सरणी के लिए एक सामान्य सूचक की तरह इस्तेमाल नहीं किया जा सकता है।


2
एफडब्ल्यूआईटी, आप केवल उपयोग करने पर भी विचार कर सकते हैं std::vector। आपको संदर्भ का उपयोग करते हुए सरणी को पास करने के लिए सावधान रहना होगा ताकि आप इसकी प्रतियां न बनाएं। डेटा तक पहुंचने के लिए सिंटैक्स, शेयर्ड_प्ट्र की तुलना में क्लीनर है, और इसे आकार देना बहुत आसान है। और आपको सभी एसटीएल अच्छाई मिलती है जो आपको कभी भी चाहिए।
निकु स्तिर्का

6
यदि सरणी का आकार संकलन समय पर निर्धारित किया गया है, तो आप उपयोग करने पर भी विचार कर सकते हैं std::array। यह लगभग एक कच्चे सरणी के समान है, लेकिन अधिकांश पुस्तकालय घटकों में उपयोग के लिए उचित शब्दार्थ के साथ है। विशेष रूप से उस प्रकार की वस्तुएं नष्ट हो जाती हैं delete, नहीं delete[]। और इसके विपरीत vector, यह डेटा को सीधे ऑब्जेक्ट में संग्रहीत करता है, इसलिए आपको कोई अतिरिक्त आवंटन नहीं मिलता है।
celtschk

जवाबों:


268

साथ सी ++ 17 , shared_ptrएक गतिशील आवंटित सरणी का प्रबंधन करने के लिए इस्तेमाल किया जा सकता है। shared_ptrइस मामले में टेम्पलेट तर्क होना चाहिए T[N]या T[]। तो आप लिख सकते हैं

shared_ptr<int[]> sp(new int[10]);

N4659 से, [use.smartptr.saring.const]

  template<class Y> explicit shared_ptr(Y* p);

आवश्यकता है: Y एक पूर्ण प्रकार होगा। एक सरणी प्रकार, या , जब एक सरणी प्रकार नहीं है delete[] p, तो अभिव्यक्ति में अच्छी तरह से परिभाषित व्यवहार होगा, और अपवाद नहीं फेंकेंगे। ... टिप्पणी: जब एक सरणी प्रकार है, यह निर्माता अधिभार संकल्प में भाग नहीं होगा जब तक कि अभिव्यक्ति अच्छी तरह से गठित है और या तो है और करने के लिए परिवर्तनीय है , या है और करने के लिए परिवर्तनीय है । ...Tdelete pT

Tdelete[] pTU[N]Y(*)[N]T*TU[]Y(*)[]T*

इसका समर्थन करने के लिए, सदस्य प्रकार element_typeअब के रूप में परिभाषित किया गया है

using element_type = remove_extent_t<T>;

ऐरे तत्वों का उपयोग करके पहुँचा जा सकता है operator[]

  element_type& operator[](ptrdiff_t i) const;

आवश्यक है: get() != 0 && i >= 0। अगर Tहै U[N], i < N। ...
टिप्पणी: जब Tकोई सरणी प्रकार नहीं है, तो यह अनिर्दिष्ट है कि क्या यह सदस्य फ़ंक्शन घोषित किया गया है। यदि यह घोषित किया जाता है, तो यह अनिर्दिष्ट है कि इसका वापसी प्रकार क्या है, सिवाय इसके कि फ़ंक्शन की घोषणा (हालांकि जरूरी नहीं कि परिभाषा) अच्छी तरह से बनाई जाएगी।


सी ++ 17 से पहले , shared_ptrहो सकता है नहीं गतिशील रूप से आवंटित सरणियों का प्रबंधन करने के लिए इस्तेमाल किया जा। डिफ़ॉल्ट रूप से, प्रबंधित ऑब्जेक्ट पर shared_ptrकॉल करेगा deleteजब कोई संदर्भ नहीं रहेगा। हालाँकि, जब आप संसाधन का उपयोग new[]करने के लिए आपको कॉल करने की आवश्यकता होती है delete[], और आवंटित नहीं deleteकरते हैं।

shared_ptrकिसी सरणी के साथ सही तरीके से उपयोग करने के लिए , आपको एक कस्टम डिलेटर की आपूर्ति करनी चाहिए।

template< typename T >
struct array_deleter
{
  void operator ()( T const * p)
  { 
    delete[] p; 
  }
};

इस प्रकार share_ptr बनाएँ:

std::shared_ptr<int> sp(new int[10], array_deleter<int>());

अब प्रबंधित वस्तु को नष्ट करने पर shared_ptrसही ढंग से कॉल करेगा delete[]

ऊपर दिए गए कस्टम डिलेटर को प्रतिस्थापित किया जा सकता है

  • std::default_deleteसरणी प्रकार के लिए आंशिक विशेषज्ञता

    std::shared_ptr<int> sp(new int[10], std::default_delete<int[]>());
  • एक लंबोदर अभिव्यक्ति

    std::shared_ptr<int> sp(new int[10], [](int *p) { delete[] p; });

इसके अलावा, जब तक आपको वास्तव में प्रबंधित ऑब्जेक्ट की शेयर ऑनरशिप की आवश्यकता नहीं होती है, unique_ptrयह इस कार्य के लिए बेहतर अनुकूल है, क्योंकि इसमें सरणी प्रकारों के लिए आंशिक विशेषज्ञता है।

std::unique_ptr<int[]> up(new int[10]); // this will correctly call delete[]

लाइब्रेरी फंडामेंटल के लिए C ++ एक्सटेंशन्स द्वारा पेश किए गए परिवर्तन

ऊपर सूचीबद्ध लोगों के लिए एक और प्री-सी ++ 17 विकल्प लाइब्रेरी फंडामेंटल्स टेक्निकल स्पेसिफिकेशन द्वारा प्रदान किया गया था , जो shared_ptrइसे ऑब्जेक्ट्स की एक सरणी का मालिक होने पर मामलों के लिए बॉक्स से बाहर काम करने की अनुमति देने के लिए संवर्धित करता था। shared_ptrइस टीएस के लिए किए गए परिवर्तनों का वर्तमान मसौदा N4082 में पाया जा सकता है । ये परिवर्तन std::experimentalनाम स्थान के माध्यम से सुलभ होंगे , और <experimental/memory>हेडर में शामिल होंगे । shared_ptrसरणियों के समर्थन के लिए कुछ प्रासंगिक परिवर्तन हैं:

- सदस्य प्रकार की परिभाषा element_typeबदल जाती है

typedef T element_type;

 typedef typename remove_extent<T>::type element_type;

- सदस्य operator[]जोड़ा जा रहा है

 element_type& operator[](ptrdiff_t i) const noexcept;

- विपरीत unique_ptrसरणियों के लिए आंशिक विशेषज्ञता, दोनों shared_ptr<T[]>और shared_ptr<T[N]>मान्य होगा और दोनों में परिणाम होगा delete[]वस्तुओं की कामयाब सरणी पर बुलाया जा रहा है।

 template<class Y> explicit shared_ptr(Y* p);

आवश्यकता है : Yएक पूर्ण प्रकार होगा। एक सरणी प्रकार, या , जब एक सरणी प्रकार नहीं है delete[] p, तो अभिव्यक्ति , अच्छी तरह से बनाई जाएगी, अच्छी तरह से परिभाषित व्यवहार होगा, और अपवाद नहीं फेंकेंगे। जब है , के लिए परिवर्तनीय होगा ; जब है , के लिए परिवर्तनीय होगा ; अन्यथा, के लिए परिवर्तनीय होगा ।Tdelete pTTU[N]Y(*)[N]T*TU[]Y(*)[]T*Y*T*


9
+1, टिप्पणी: इसमें बूस्ट भी है shared-array
जोगोजापान

5
@ tshah06 shared_ptr::getप्रबंधित ऑब्जेक्ट के लिए एक पॉइंटर लौटाता है। आप के रूप में उपयोग कर सकते हैं तोsp.get()[0] = 1; ... sp.get()[9] = 10;
Praetorian

55
एएलटी: std::shared_ptr<int> sp( new int[10], std::default_delete<int[]>() );यह भी देख en.cppreference.com/w/cpp/memory/default_delete
yohjp

2
@ जेरेमी अगर आकार संकलन के समय में जाना जाता है, तो उसके लिए एक वर्ग लिखने की आवश्यकता नहीं है, std::shared_ptr<std::array<int,N>>पर्याप्त होना चाहिए।
प्रेटोरियन

13
unique_ptrवह आंशिक विशेषज्ञता क्यों प्राप्त करता है लेकिन shared_ptrनहीं करता है?
एडम

28

एक संभवतः आसान विकल्प जो आप उपयोग करने में सक्षम हो सकते हैं shared_ptr<vector<int>>


5
हाँ यही है। या एक वेक्टर एक सरणी का एक सुपरसेट है - इसमें एक ही इन-मेमोरी प्रतिनिधित्व (प्लस मेटाडेटा) है, लेकिन पुन: प्रयोज्य है। वास्तव में ऐसी कोई भी स्थिति नहीं है जहाँ आप एक सरणी चाहते हैं, लेकिन एक वेक्टर का उपयोग नहीं कर सकते।
टिमम्म

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

4
तब आप शायद उपयोग कर सकते हैं shared_ptr<array<int, 6>>
टिम्मम

10
दूसरा अंतर यह है कि यह कच्चे सरणी की तुलना में थोड़ा बड़ा और धीमा है। आम तौर पर वास्तव में कोई मुद्दा नहीं है लेकिन चलो यह नहीं दिखाते हैं कि 1 == 1.1।
एंड्रयू

2
ऐसी परिस्थितियां हैं जहां सरणी में डेटा के स्रोत का मतलब है कि वेक्टर में कनवर्ट करना अनजाने में या अनावश्यक है; जैसे कि कैमरे से फ्रेम प्राप्त करते समय। (या, यह मेरी समझ है, वैसे भी)
Narfanator
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.