2012-12-13 18 views

उत्तर

15

जवाब [unique.ptr.single.assign] में कदम असाइनमेंट के मानक के विनिर्देश/2 से स्पष्ट होना चाहिए: के रूप में अगर reset(u.release()) फोन करके स्थानांतरण स्वामित्व u से *this रहे हैं:

प्रभाव std::forward<D>(u.get_deleter()) से असाइनमेंट के बाद।

स्पष्ट रूप से असाइनमेंट reset(u.release()) जैसा नहीं है क्योंकि यह कुछ अतिरिक्त करता है।

अतिरिक्त प्रभाव महत्वपूर्ण है, यह बिना आप कस्टम deleters साथ अपरिभाषित व्यवहार प्राप्त कर सकते हैं:

#include <cstdlib> 
#include <memory> 

struct deleter 
{ 
    bool use_free; 
    template<typename T> 
    void operator()(T* p) const 
    { 
     if (use_free) 
     { 
     p->~T(); 
     std::free(p); 
     } 
     else 
     delete p; 
    } 
}; 

int main() 
{ 
    std::unique_ptr<int, deleter> p1((int*)std::malloc(sizeof(int)), deleter{true}); 
    std::unique_ptr<int, deleter> p2; 
    std::unique_ptr<int, deleter> p3; 

    p2 = std::move(p1); // OK 

    p3.reset(p2.release()); // UNDEFINED BEHAVIOUR! 
} 
5

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

+0

क्या आप एक उदाहरण दे सकते हैं क्यों यह खतरनाक है? – Ali

+0

यह मानक में लिखा गया है कि मुझे कॉल करने की अनुमति है, उदाहरण के लिए 'move()' के बाद 'p2' पर 'रीसेट()'? – Ali

+3

@Ali चूंकि 'रीसेट' में कोई पूर्व शर्त नहीं है, इसलिए आप इसे हमेशा कॉल कर सकते हैं, क्योंकि किसी भी चाल को किसी अनिर्धारित लेकिन मान्य ** स्थिति में ऑब्जेक्ट से स्थानांतरित करने के लिए निर्दिष्ट किया गया है, जो बिना किसी फ़ंक्शन का उपयोग करता है पूर्व शर्त हमेशा मान्य है। यह केवल कुछ पूर्व शर्त पर निर्भर करता है (जैसे पॉइंटर 'नलप्टर' होता है, लेकिन हो सकता है कि मानक द्वारा 'std :: unique_ptr' के लिए भी गारंटी दी जाए) जिसके लिए आपको पहले संबंधित स्थिति की जांच करनी होगी। मूविंग किसी ऑब्जेक्ट को किसी भी तरह से अमान्य नहीं करता है, यह एक सामान्य गलतफहमी है। किसी भी कदम के बाद –

-2

दूसरा संस्करण अपवाद सुरक्षित नहीं हो सकता है, मुझे लगता है।

auto __tmp = p2.release(); 
p1.reset(__tmp); 

इस प्रकार अगर std::unique_ptr::reset करने के लिए कॉल फेंकता है (जैसा भी मामला हो सकता है, तो प्रबंधित वस्तु का विलोपन फेंकता है), तो आप एक unreferred वस्तु जो कभी नष्ट नहीं किया जाएगा है: यह के बराबर है। चाल असाइनमेंट के मामले में, std::unique_ptr वास्तविक कदम के साथ प्रतीक्षा कर सकते हैं (और चाहिए) p1 की मूल वस्तु ठीक से नष्ट हो गई है।

लेकिन ध्यान दें, यह केवल एक समस्या है यदि प्रबंधित ऑब्जेक्ट का विनाशक फेंक सकता है, जो लगभग सभी मामलों में गलत है, या यदि आप कस्टम डिलीटर का उपयोग कर सकते हैं जो फेंक सकता है। तो अभ्यास में आमतौर पर दो कोड स्निपेट के बीच कोई व्यवहार अंतर नहीं होता है।


संपादित करें: अंत जोनाथन उसकी टिप्पणी में बताते हैं, उस कस्टम Deleter मानक के लिए आवश्यक है फेंकने के लिए नहीं है, जो वास्तव में std::unique_ptr::reset बहुत संभावना नहीं/गैर अनुरूप की फेंकने बना देता है। लेकिन वह यह भी बताते हैं कि एक और अंतर है, जिसमें केवल एक चाल असाइनमेंट किसी भी कस्टम डेलेटर्स को भी ले जाता है, जिसके लिए उन्होंने एक जवाब भी लिखा है।


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

+0

_ देखें "इसलिए व्यवहार में आमतौर पर दो कोड स्निपेट्स के बीच कोई व्यवहारिक अंतर नहीं होता है ._" यह सच नहीं है, कोई डिलीटर चलाता है और कोई नहीं करता है। यदि डिलीटर राज्यपूर्ण है तो यह बहुत महत्वपूर्ण है। –

+2

योको, 'std :: unique_ptr' के चाल असाइनमेंट ऑपरेटर को" रीसेट (u.release()) '[...] को कॉल करके 'u' से' * 'के रूप में स्वामित्व स्थानान्तरण के रूप में निर्दिष्ट किया गया है। "। मानक फेंकने वाले विनाशकों पर भारी निर्भर करता है। – Xeo

+0

@ जोनाथन वाकली हां, ठीक है! कस्टम deleters के बारे में बहुत ज्यादा नहीं सोचा था। –

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