2015-02-05 5 views
7
#include <memory> 
#include <iostream> 

struct A : public std::enable_shared_from_this<A> 
{ 
    ~A() 
    { 
     auto this_ptr = shared_from_this(); // std::bad_weak_ptr exception here. 
     std::cout << "this: " << this_ptr; 
    } 
}; 

int main() 
{ 
    auto a = std::make_shared<A>(); 
    a.reset(); 
    return 0; 
} 

shared_from_this() पर कॉल करते समय मुझे std::bad_weak_ptr अपवाद मिल रहा है। क्या यह डिजाइन द्वारा है? हां, यह खतरनाक हो सकता है क्योंकि इस सूचक का उपयोग विनाशक रिटर्न के बाद नहीं किया जा सकता है, लेकिन मुझे कोई कारण नहीं दिख रहा है कि यह पॉइंटर प्राप्त करने के लिए तकनीकी रूप से असंभव क्यों होगा, क्योंकि साझा पॉइंटर ऑब्जेक्ट स्पष्ट रूप से अभी भी मौजूद है और हो सकता है उपयोग किया गया। क्या इसे रोकने के लिए कोई रास्ता है, अपना खुद का enable_shared_from_this एनालॉग लिखने से कम (जो मैं नहीं करूँगा)?std :: enable_shared_from_this: क्या इसे destructor में shared_from_this() को कॉल करने की अनुमति है?

+0

http://stackoverflow.com/q/8501503/1147772 – Drax

+0

@Drax: मैंने यह प्रश्न देखा है। यह 'बूस्ट' से संबंधित है और 'std' नहीं है, और उत्तर 'shared_from_this()' उपलब्धता पर मूल सीमाओं के बजाय प्रश्न के कोड के विशिष्ट डिज़ाइन के बारे में बात करते हैं। –

+0

@VioletGiraffe प्रश्न न तो 'बूस्ट' और न ही 'std', केवल कमजोर संदर्भ की अवधारणा से संबंधित है। – curiousguy

उत्तर

6

मुझे कोई कारण नहीं दिख रहा है कि यह पॉइंटर प्राप्त करने के लिए तकनीकी रूप से असंभव क्यों होगा, क्योंकि साझा पॉइंटर ऑब्जेक्ट स्पष्ट रूप से अभी भी मौजूद है और इसका उपयोग किया जा सकता है।

एक बहुत अच्छा तकनीकी कारण है कि यह संभव क्यों नहीं है।

shared_ptr मौजूद हो सकता है, लेकिन A ऑब्जेक्ट के लिए संदर्भ संख्या शून्य तक पहुंच गई है, यही कारण है कि विनाशक चलाया जा रहा है। एक बार जब संदर्भ गणना शून्य तक पहुंच जाती है तो इसे फिर से नहीं बढ़ाया जा सकता है (अन्यथा आप shared_ptr प्राप्त कर सकते हैं जो किसी ऑब्जेक्ट को संदर्भित करता है जो या तो इसके विनाशक को चलाने के बीच में होता है, या पहले ही नष्ट हो चुका है)।

shared_from_this() की कोशिश करता कॉलिंग संदर्भ संख्या में वृद्धि और एक shared_ptr है कि वर्तमान स्वामी (रों) के साथ स्वामित्व के शेयरों लौटने के लिए, लेकिन आप एक शून्य से काउंटर नहीं बढ़ा सकते हैं करने के लिए, तो यह विफल रहता है।

में यह बहुत ही विशेष मामले (वस्तु नाशक अंदर) क्या आप जानते वस्तु पूरी तरह से अभी तक नहीं नष्ट कर दिया गया है, लेकिन enable_shared_from_this<A> कोई रास्ता नहीं पता है, जो shared_from_this() समारोह बुला रहा है है, तो अगर यह पता नहीं कर सकते हैं में यह बहुत विशिष्ट मामला या ऑब्जेक्ट के विनाशक के बाहर कोड के किसी अन्य भाग में हो रहा है (उदाहरण के लिए एक और थ्रेड जो विनाशक के बाद जा रहा है)।

आप किसी भी तरह यह इस विशेष मामले के लिए काम कर सकता है और आप एक shared_ptr<A> उस वस्तु वर्तमान में नष्ट किया जा रहा करने के लिए भेजा मिल गया है, तो आप दे सकते हैं कि नाशक है कि यह बाद में उपयोग के लिए भंडारित बाहर कुछ करने के लिए shared_ptr। ऑब्जेक्ट नष्ट होने के बाद, उस कोड के दूसरे भाग को खतरे में डालकर shared_ptr तक पहुंचने की अनुमति मिल जाएगी। यह shared_ptr और weak_ptr प्रकार सिस्टम में एक बड़ा छेद होगा।

+0

ग्रेट स्पष्टीकरण, धन्यवाद। –

0

shared_ptr::reset के कार्यान्वयन अक्सर shared_ptr().swap(*this) है।

जिसका अर्थ है कि shared_ptr आप प्रतिलिपि बनाने की कोशिश कर रहे हैं पहले से ही इसके विनाशक राज्य में है जो बदले में आपके विनाशक को बुलाए जाने से पहले साझा गणना को कम करता है। जब आप enable_shared_from_this फोन यह जब गिनती 0.

तो आपके प्रश्न का उत्तर है कि weak_ptr जो एक अपवाद में परिणाम से एक shared_ptr का निर्माण करके बढ़ावा देने के लिए weak_ptr यह भीतर संग्रहीत की कोशिश करेंगे, वहाँ करने का कोई मानक तरीका है क्या आप चाहते हैं कि आपका मानक लाइब्रेरी कार्यान्वयन इस तरह से व्यवहार न करे जो इसे अधिकृत करता है (मुझे नहीं पता कि यह मानक द्वारा अनिवार्य है या नहीं)।

अब, यहाँ एक हैक है कि मेरे मशीन (बजना/libC++) पर काम करता है:

#include <memory> 
#include <iostream> 

class hack_tag 
{ 
}; 

namespace std 
{ 

    template<> 
    class shared_ptr<hack_tag> 
    { 
    public: 
    template<typename T> 
    weak_ptr<T>  extract_weak(const enable_shared_from_this<T>& shared) 
    { 
     return shared.__weak_this_; 
    } 
    }; 

}; 

using weak_ptr_extractor = std::shared_ptr<hack_tag>; 

class test : public std::enable_shared_from_this<test> 
{ 
public: 
    test() 
    { 
    std::cout << "ctor" << std::endl; 
    } 

    ~test() 
    { 
    std::cout << "dtor" << std::endl; 
    weak_ptr_extractor hacker; 
    auto weak = hacker.extract_weak(*this); 
    std::cout << weak.use_count() << std::endl; 
    auto shared = weak.lock(); 
    } 
}; 


int  main(void) 
{ 
    std::shared_ptr<test> ptr = std::make_shared<test>(); 

    ptr.reset(); 
} 

लेकिन मैं के बारे में है तो आप अपने मालिक shared_ptr है कि आप की नकल की के बाद से कुछ भी है कि के साथ उपयोगी कर सकते हैं यकीन नहीं है मरने के लिए और वह प्रति नईके साथ चीजों को साझा नहीं करती है, आपको reset कॉल के बाद मिलता है।

9

[util.smartptr.enab]/7 shared_from_this के लिए पूर्व शर्त वर्णन करता है:

आवश्यक है:enable_shared_from_this<T>T का एक सुलभ आधार वर्ग होगा। *thisT प्रकार के ऑब्जेक्ट t का सबबोजेक्ट होगा। कम से कम एक shared_ptr उदाहरण p होगा जो &t का मालिक होगा। [emph। जोड़ा गया]

चूंकि आपकी वस्तु नष्ट हो रही है, इसलिए यह होना चाहिए कि shared_ptr कोई स्वामित्व नहीं है। नतीजतन, आप उस आवश्यकता का उल्लंघन किए बिना shared_from_this पर कॉल नहीं कर सकते जिसके परिणामस्वरूप अपरिभाषित व्यवहार होता है।

+1

"चूंकि आपकी ऑब्जेक्ट नष्ट हो रही है, इसलिए यह मामला होना चाहिए कि इसमें कोई 'shared_ptr' नहीं है जिसका स्वामित्व है।" जब तक कि कोई स्पष्ट विनाशक कॉल करने के लिए पर्याप्त पागल न हो;) –

+1

@ टी.सी. यदि ऐसा है, तो "कोई" स्पष्ट रूप से सोचता है कि * वे वास्तव में स्वामी हैं, न कि 'shared_ptr' जो ऑब्जेक्ट को संदर्भित करता है। मेरा तर्क खड़ा है;) – Casey

+0

मेरी सोच यह थी कि चूंकि 'shared_ptr' किसी ऑब्जेक्ट को नष्ट करने के लिए ज़िम्मेदार है, इसलिए पॉइंटर तब तक नष्ट नहीं होगा जब तक उसके द्वारा रखी गई वस्तु को हटा दिया नहीं जाता है। लेकिन जाहिर है, संदर्भ काउंटर ऑब्जेक्ट उस से पहले नष्ट हो गया है, कम से कम एमएस कार्यान्वयन में, इसलिए यह विनाशक में पहले से ही अनुपलब्ध है। –

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