2013-04-03 6 views
8

मान लें कि मेरे पास कक्षा है।क्या मैं किसी ऑब्जेक्ट को shared_ptr में रीसेट करने के लिए प्लेसमेंट नया उपयोग कर सकता हूं?

class BigData {...}; 
typedef boost::shared_ptr<BigData> BigDataPtr; 

तो मैं कार्य करें:

BigDataPtr bigDataPtr(new BigData()); 

बाद में के बाद मैं अपने वस्तु के साथ किया हूँ और मैं वहाँ यकीन है कि वस्तु के लिए कोई अन्य उपयोगकर्ताओं कर रहा हूँ।

bigDataPtr->~BigDataPtr(); 
new (&*bigDataPtr) BigData; 

यह मेरे किसी भी अतिरिक्त आवंटन के बिना वस्तु रीसेट करते हैं:

यह निम्न करने के लिए सुरक्षित है?

+1

'bigDataPtr = BigData(); 'के साथ क्या गलत है? – jrok

+0

काफी समान प्रश्न है, लेकिन मैं के रूप में डुप्लिकेट पर विचार नहीं करते: http://stackoverflow.com/questions/1124634/c-call-destructor-and-then-constructor-resetting-an-object – PiotrNycz

+3

आपका मतलब है 'bigDataPtr-> ~ BigData(); '? साथ ही, 'BigData' के लिए बस कुछ' रीसेट 'विधि क्यों न प्रदान करें? – zch

उत्तर

2

हाँ, यह सामान्य रूप से सुरक्षित है।

नोट नीचे

बूस्ट टाइपो संदेश भिन्नता और के रूप में

template<class T> 
typename boost::detail::sp_dereference<T>::type boost::shared_ptr<T>::operator*() const; 

template<class T> 
typename boost::detail::sp_member_access<T>::type boost::shared_ptr<T>::operator->() const; 

-> ऑपरेटरों जब उन detail बिट्स को परिभाषित करता है (एक फेंकने बढ़त मामले के बारे में मैक्सिम Yegorushkin का अवलोकन करने के लिए नोड) हल हो गए हैं, आपके पास यह

है 0

तो आप सीधे ऑब्जेक्ट से ऑब्जेक्ट से निपट रहे हैं। कोई प्रॉक्सी या अन्य संरचनाएं नहीं हैं जो आप कोशिश कर रहे हैं में हस्तक्षेप कर सकती हैं।

के रूप में उठाई-करने के लिए डेटा का संबंध है, अपने कोड:

bigDataPtr->~BigDataPtr(); 
new (&*bigDataPtr) BigData; 

लिखने में कोई त्रुटि मिल सकता है।लेकिन अगर आप का इरादा:

bigDataPtr->~BigData(); 
new (&*bigDataPtr) BigData; 

यह

(BigData pointer)->~BigData(); 
new (&(BigData reference)) BigData; 

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

+0

आपके कोड उदाहरण को '~ BigData()' का उपयोग करने की आवश्यकता है। –

+0

@ डेव्स हाँ! अच्छी नज़र। –

+0

यह भी जानते हैं कि यह प्रकार 'BigData' पर निर्भर करता है होना करने के लिए महत्वपूर्ण है। यह यूबी में परिणाम अगर वहाँ 'BigData' में किसी भी' const' या संदर्भ गैर स्थिर डेटा सदस्य हैं (या उसके ठिकानों या सदस्यों, रिकर्सिवली)। 'रीसेट() ' –

2

यह सुरक्षित है अगर BigData निर्माता और नाशक अपवाद फेंक नहीं है और bigDataPtr धागे और कोई संकेत या संदर्भ के बीच साझा नहीं है गतिशील रूप से आवंटित करने के लिए BigData के सदस्य (यदि हो तो) मौजूद हैं।

यदि विनाशक अपवाद फेंकता है तो आप आंशिक रूप से नष्ट वस्तु के साथ समाप्त हो सकते हैं (विनाशकों को फेंकने की आमतौर पर अनुशंसा नहीं की जाती है और मानक कंटेनर की आवश्यकता होती है कि तत्वों के विनाशक फेंक न दें)।

यदि निर्माता फेंकता है तो आप ऑब्जेक्ट को नष्ट कर सकते हैं लेकिन एक नया निर्माण नहीं कर सकते हैं।

यदि bigDataPtr धागे के बीच साझा किया जाता है जो एक लॉकिंग अनुशासन का उपयोग नहीं किया जाता है जब तक दौड़ की स्थिति का कारण बन सकता है।

कोड कहीं और संदर्भ या संकेत गतिशील आवंटित करने के लिए BigData के सदस्यों, जब यह एक नया BigData अपनी गतिशील आवंटित सदस्यों अन्य पते पर आवंटित किया जा सकता है बनाता है, इसलिए मौजूदा संकेत और सदस्यों के लिए संदर्भ अमान्य हो लेता है।

आप new (&*bigDataPtr) BigData; बयान में संदिग्ध भिन्नता को लेकर चिंतित हैं तो इसके बजाय एक सादे सूचक का उपयोग करें:

BigData* p = bigDataPtr.get(); 
p->~BigData(); 
new (p) BigData; 
+0

"फेंक विनाशकर्ता आम तौर पर सिफारिश कर रहे हैं नहीं और मानक कंटेनर की आवश्यकता है कि तत्वों की विनाशकर्ता फेंक नहीं है" - वास्तव में, यह भाषा की अनुमति नहीं देतीं कि विनाशकर्ता फेंक है - एक अपवाद एक नाशक 'एसटीडी निकल जाता है, तो :: terminate' कहा जाता है। –

6

इस बारे में जाने के कुछ तरीके हैं। आप नियुक्ति नई उपयोग कर सकते हैं, और इस दो कारणों के लिए सुरक्षित होने की गारंटी है:

  1. आप पहले से ही वस्तु के लिए स्मृति आवंटित ताकि आप जानते हैं कि यह आकार और सही ढंग से गठबंधन है।

  2. shared_ptr गैर-आक्रामक है; इसकी एकमात्र जिम्मेदारी संदर्भों की गणना करना और आवश्यक होने पर हटा देना है।

हालांकि, पर विचार क्या हुआ अगर वस्तु के पुनर्निर्माण हो सकता है विफल रहता है-यानी, एक अपवाद फेंकता है: Deleter एक गैर निर्माण वस्तु पर कहा जा सकता है:

bigDataPtr->~BigDataPtr(); 
new (bigDataPtr.get()) BigData; 

तो फिर तुम एक समस्या है , निश्चित रूप से अनिश्चित व्यवहार के लिए लगभग निश्चित रूप से अग्रणी है। मैं "लगभग" कहता हूं क्योंकि डिलीटर नो-ऑप हो सकता है, इस मामले में सभी ठीक होंगे।

*bigDataPtr = BigData(42); 

या एक reset() सदस्य समारोह BigData में जोड़ें:

bigDataPtr->reset(42); 

तो यह स्पष्ट क्या तुम्हारा असली

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

+0

+1 एक अच्छा विचार है, लेकिन फिर सवाल अभी भी खड़ा है, उस फ़ंक्शन को कैसे कार्यान्वित करें। प्रश्नकर्ता का कोड (कम से कम सतही रूप से, सभी भयानक चेतावनी को अनदेखा कर रहा है कि यह कैसे गलत हो सकता है) ऐसा करने का एक तरीका है। – IronMensan

+0

' रीसेट 'फ़ंक्शन जोड़ने के लिए –

+0

@SteveJessop: ज़रूर। अतीत में मैंने एक टेम्पलेट 'नवीनीकरण' समारोह भी बनाया है, जैसे 'टेम्पलेट <कक्षा टी, कक्षा ... Args> शून्य नवीकरण (टी * कॉन्स पी, Args && ... args) {p-> ~ टी (); नया (पी) (std :: आगे (तर्क) ...); } 'लेकिन इसे अपवाद-सुरक्षित बनाना वास्तव में संभव नहीं है। –

1

सबसे पहले, अगर निर्माता फेंकता है और वर्ग तुच्छ रूप से विनाशकारी नहीं है तो आपको एक समस्या है, क्योंकि shared_ptr इसे "हटाना" चाहता है, जो यूबी को उकसाएगा।

तो आपको एक नोट्रो कन्स्ट्रक्टर का उपयोग करके या किसी अपवाद को पकड़कर और ऑब्जेक्ट को हटाने से स्मार्ट पॉइंटर को रोककर उस से निपटना होगा। चूंकि shared_ptr में release() फ़ंक्शन नहीं है, इसलिए ऐसा करना आसान है। यदि आप सभी विफल हो जाते हैं तो आप terminate() पर कॉल कर सकते हैं, लेकिन इससे आपको अपने उपयोगकर्ताओं के साथ लोकप्रिय नहीं बनाया जाएगा।

यदि ऑब्जेक्ट के कोई अन्य संदर्भ नहीं हैं, तो यह काम करेगा, बशर्ते कक्षा में const या गैर-स्थैतिक डेटा सदस्यों (सदस्यों के सदस्यों सहित) का संदर्भ न हो। कारण 3.8/7:

हैं, तो एक वस्तु का जीवन समाप्त हो गया है और भंडारण जो वस्तु पर कब्जा कर लिया पुन: उपयोग या जारी किया गया है से पहले, एक नई वस्तु भंडारण स्थान जो मूल में बनाया है के बाद ऑब्जेक्ट पर कब्जा कर लिया गया, पॉइंटर जो मूल ऑब्जेक्ट को इंगित करता है ... पर नए ऑब्जेक्ट में हेरफेर किया जा सकता है, यदि ... मूल ऑब्जेक्ट का प्रकार कॉन्स्ट-क्वालिटी नहीं है, और, यदि कोई वर्ग प्रकार करता है, करता है कोई गैर स्थैतिक डेटा सदस्य नहीं है जिसका प्रकार कॉन्स्ट-क्वालिफ़ाई है या संदर्भ प्रकार है ...

ध्यान दें कि shared_ptr सिर्फ इस तरह के एक सूचक है, जो यह नई वस्तु है, जो यूबी है अगर 3.8/7 में से कोई भी शर्त टूट गया है हेरफेर करने के लिए इस्तेमाल करेगा आयोजित करता है। टूटा जा सकता है केवल एक ही यह है, आप अपने कोड के बारे में जो कहा है उसके साथ बाकी को कवर किया है। विशेष रूप से, यह आवश्यक है कि आप एक वर्ग BigData से प्राप्त BigData का एक उदाहरण के रूप में मूल वस्तु, नहीं बनाया है, क्योंकि नई वस्तु पुराने एक के रूप में एक ही सबसे व्युत्पन्न प्रकार की आवश्यकता है।

आमतौर पर इस से एक वस्तु पुनर्स्थापित करने के लिए और अधिक मजबूत तरीके हैं। उदाहरण के लिए, operator= (copy- या चाल असाइनमेंट ऑपरेटर) को लागू करने और उसके बाद *bigDataPtr = BigData() लिखें। बेशक यह काफी तेज़ नहीं हो सकता है।

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

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