2010-11-16 4 views
6

मुझे साझा_ptr के बारे में कुछ उलझन में मिला है। !shared_ptr का उपयोग करने के लिए, क्या यह सुरक्षित है?

class foo { 
    int _f; 
}; 
typedef std::shared_ptr<foo> fooptr; 

class bar { 
    int _b; 
}; 
typedef std::shared_ptr<bar> barptr; 

class foobar : public foo, public bar { 
    int _fb; 
}; 

int main() { 

    foobar *fb1 = new foobar(); 
    foobar *fb2 = new foobar(); 

    fooptr f((foo *)fb1); 
    barptr b((bar *)fb2); 

    return 0; 
} 

क्योंकि b.get() = FB2, तो यह दुर्घटना चाहिए जब कार्यक्रम से बाहर निकलें:

कहो, मैं वर्गों है? या यह सुरक्षित है?

उत्तर

10

shared_ptr<base> सुरक्षित रूप से derived* का स्वामित्व ले सकता है, भले ही base में वर्चुअल विनाशक न हो।

हालांकि, यह केवल तभी काम करता है जब shared_ptr जानता है कि वस्तु का सबसे व्युत्पन्न प्रकार क्या होता है जब यह स्वामित्व लेता है। यदि आप

fooptr f(fb1); 
fooptr b(fb2); 

को हटा देना चाहते हैं तो आप निश्चित रूप से ठीक होंगे।डाले के साथ, shared_ptr क्या वस्तु का सबसे व्युत्पन्न प्रकार है जब यह के स्वामित्व लेता है पता नहीं कर सकते, तो व्यवहार अपरिभाषित है, जैसे कि आपने कहा था:

foo* f = new foobar(); 
delete f; 

सबसे अच्छी बात करने के लिए नियम का पालन करना है कि "a base class destructor should be either public and virtual, or protected and nonvirtual."

+0

+1, आपने टेम्पलेट कन्स्ट्रक्टर को समझाते हुए मुझे हराया। –

+0

आपके उत्तर के लिए धन्यवाद :) – ddh

0

foo और bar पॉलिमॉर्फिक कक्षाएं नहीं हैं और इसलिए इस कोड का परिणाम अमान्य सूचक डीलोकेशन में होगा।

7

नहीं, यह सुरक्षित नहीं है। foo और bar आभासी विनाशकों की आवश्यकता है, अन्यथा यह अनिश्चित है कि क्या होता है जब shared_ptr का विनाशक उस सूचक को हटा देता है जो उसके होल्डिंग को हटा देता है। बेशक, यह कहकर कि यह सुरक्षित नहीं है, यह कहने के समान नहीं है कि इसे दुर्घटनाग्रस्त होना चाहिए।

वैकल्पिक रूप से, वहाँ कुछ जादू है [*] shared_ptr में बनाया गया है जिसका अर्थ है कि यदि आप foo* में ढाला नहीं है, तो अपने कोड सुरक्षित हो जाता है:

fooptr f(fb1); 
barptr b(fb2); 

या तो आभासी नाशक के साथ, या बाहर ले करता है, तो कास्ट, जब share_ptr सूचक को हटाने के लिए आता है, तो संकलक सही विध्वंसकर्ताओं को कॉल करने और स्मृति मुक्त करने के लिए, सूचक को अपने मूल प्रकार पर वापस समायोजित करने के बारे में "पता" करेगा।

जादू केवल काम करता है क्योंकि fb1 टाइप foobar* है, हालांकि। आभासी नाशक के बिना, निम्नलिखित अभी भी असुरक्षित है:

fooptr f(new foobar()); 

आप भी अपने कोड में है कि समस्या से बचने कर सकते हैं:

foo *fb = new foobar(); 
fooptr f(fb); 

आप shared_ptr इस तरह उपयोग करते हैं, तो उस करने का कोई खतरा है , यदि new foobar() पर दूसरा कॉल अपवाद फेंकता है, तो पहली वस्तु लीक हो जाती है। आप shared_ptr उपयोग करने के लिए आप के लिए स्मृति का प्रबंधन करने जा रहे हैं, तो आप जल्दी से जल्दी प्रबंधन के तहत स्मृति प्राप्त करने की आवश्यकता:

fooptr f(new foobar()); 
barptr b(new foobar()); 

अब अगर दूसरी पंक्ति फेंकता है, f ठीक से विलुप्त हो जाएगा और नष्ट करेगा उदेश्य।

[*] "जादू" = एक कन्स्ट्रक्टर टेम्पलेट, जो shared_ptr में एक फ़ंक्शन के लिए एक पॉइंटर में संग्रहीत करता है जो संग्रहित पॉइंटर को सही प्रकार पर वापस लाएगा, और उसके बाद इसे हटा देगा।

+0

यदि फू और बार दोनों में वर्चुअल विनाशक है, तो यह सुरक्षित है? – ddh

+0

स्पष्ट कास्ट बंद करें, हालांकि, और यह सुरक्षित है क्योंकि 'shared_ptr' में एक टेम्पलेटेड कन्स्ट्रक्टर है जो मूल रूप से कन्स्ट्रक्टर को पास किए गए पॉइंटर के प्रकार के माध्यम से विनाश सुनिश्चित करता है, न कि' shared_ptr' का टेम्पलेट तर्क जो आखिरकार फाइनल का कारण बनता है विनाश। आधार वर्गों में आभासी विनाशक होने के लिए अभी भी अत्यधिक सलाह दी जाती है; लेकिन यह तकनीकी रूप से खतरनाक नहीं है। –

+0

मुझे लगता है कि shared_ptr के विनाशक में, "पीटीआर हटाएं" होना चाहिए, और हटाने का ऑपरेशन करें: 1) ऑब्जेक्ट के विनाशक को कॉल करें, और 2) स्मृति को मुक्त करें। लेकिन अगर आवंटित स्मृति 0x10000 है, लेकिन क्या साझा_प्टर प्राप्त 0x10004 है, तो कुछ समस्या हो सकती है? – ddh

-1

यह सुरक्षित नहीं है क्योंकि आप सी ++ कोड में सी-स्टाइल कास्ट का उपयोग कर रहे हैं।

सी शैली डाली प्रयोग नहीं करते, उपयोग जैसे static_cast, dynamic_cast, const_cast या reinterpret_cast डाले। प्लस, कोई क्रैश सुरक्षा का मतलब नहीं है।

वास्तव में, इस मामले में केवल जानवरों को हटा दें।

+0

'dynamic_cast' वर्तनी' dynamic_cast', अवधि है। – curiousguy