2010-11-15 8 views
6

जब भी मैं एक वेक्टर मुझे लगता है कि निम्नलिखित तरीके से कर रहा हूँ में गतिशील रूप से आवंटित वस्तु जोड़ने की जरूरत:क्या यह वेक्टर के लिए push_back 'गतिशील आवंटित ऑब्जेक्ट' को सुरक्षित है?

class Foo { ... }; 

vector<Foo*> v; 

v.push_back(new Foo); 

// do stuff with Foo in v 

// delete all Foo in v 

यह सिर्फ काम किया है और कई अन्य लोगों के एक ही बात करने के लिए लग रहे हैं।

आज, मैंने वेक्टर :: push_back को अपवाद फेंक दिया है। इसका मतलब है कि ऊपर दिया गया कोड अपवाद सुरक्षित नहीं है। :-(तो मैं एक समाधान के साथ आया था:

class Foo { ... }; 

vector<Foo*> v; 
auto_ptr<Foo> p(new Foo); 

v.push_back(p.get()); 
p.release(); 

// do stuff with Foo in v 

// delete all Foo in v 

लेकिन समस्या यह है कि नया तरीका, वर्बोज़ कठिन है, और मैं देख रहा हूँ कोई भी यह कर रहा है है (कम से कम मेरे चारों ओर नहीं ...)

मैं नए तरीके के साथ जाना चाहिए?
या, मैं सिर्फ पुराने तरीके के साथ छड़ी कर सकते हैं?
या, यह ऐसा करने का एक बेहतर तरीका है?

+0

कृपया यह भी देखें: [क्यों यह गलत एसटीएल कंटेनर के साथ std :: auto_ptr <> उपयोग करने के लिए है?] [1] [1]: http://stackoverflow.com/questions/111478/why-is -यह-गलत के लिए उपयोग-stdauto-ptr-साथ-STL-कंटेनर –

+1

@Martin: वास्तव में, '' auto_ptr' के उपयोग और यहाँ vector' (मेरा मतलब है, उनकी बातचीत के लिए विशिष्ट) के साथ कोई समस्या नहीं है के बाद से यह 'वेक्टर >' नहीं है जिसके बारे में हम बात कर रहे हैं। –

+0

@Matthieu: आप सही हैं। तो फिर मैं बचा * कह * वहाँ एक मुद्दा है, हालांकि मेरी कड़ी शायद :-) –

उत्तर

11

यदि सब आप ध्यान इस आपरेशन के अपवाद-सुरक्षा है:

v.reserve(v.size()+1); // reserve can throw, but that doesn't matter 
v.push_back(new Foo); // new can throw, that doesn't matter either. 

एक सदिश एक अलग बात को मुक्त वस्तुओं इसकी सामग्री द्वारा की ओर इशारा कर रहा है के लिए जिम्मेदारी होने का मुद्दा है, मैं तुम्हें यकीन है कि 'कि ;-)

संपादित करें के बारे में सलाह के बहुत प्राप्त करेंगे: हम्म, मैं मानक उद्धृत करने के लिए जा रहा था, लेकिन मैं वास्तव में आवश्यक गारंटी नहीं मिल रहा। क्या मैं के लिए देख रहा हूँ, जब तक या तो (क) यह पुनः आवंटित करने के लिए है (जो हम जानते हैं कि यह इसलिए नहीं कि क्षमता का होगा) कि push_back फेंक नहीं करेगा, या (ख) टी के एक निर्माता फेंकता है (जो हम जानते हैं कि यह जीत हासिल की है टी टी के बाद एक सूचक प्रकार है)। उचित लगता है, लेकिन उचित! = गारंटीकृत।

तो, जब तक कि वहाँ इस सवाल पर एक लाभदायक जवाब खत्म हो गया:

Is std::vector::push_back permitted to throw for any reason other than failed reallocation or construction?

इस कोड कार्यान्वयन कुछ भी भी "कल्पनाशील" नहीं कर रही पर निर्भर करता है। उसमें असफल होने पर सवाल से अपने समाधान अप टेम्प्लेट की जा सकती है:

struct Bar : Foo { }; 

vector<Foo*> v; 
push_back_new<Foo>(v); 
push_back_new<Bar>(v); 

तो यह वास्तव में एक कारखाने समारोह बल्कि है से new तो आप टेम्पलेट संशोधित कर सकते हैं:

template <typename T, typename Container> 
void push_back_new(Container &c) { 
    auto_ptr<T> p(new T); 
    c.push_back(p.get()); 
    p.release(); 
} 

प्रयोग तो भी कठिन नहीं है तदनुसार। हालांकि, विभिन्न परिस्थितियों में कई अलग-अलग पैरामीटर सूचियां पास करना मुश्किल होगा।

+0

हां, इस प्रश्न के लिए, मुझे केवल अपवाद-सुरक्षा की परवाह है। धन्यवाद! – upriser

0

कैसे स्मृति की कमी के लचीला अपने कार्यक्रम है? तो आप वास्तव में इसके बारे में परवाह करते हैं आपको new के लिए भी फेंकने के लिए तैयार रहना होगा। अगर आप इसे संभालने के लिए नहीं जा रहे हैं, मैं push_back हुप्स के माध्यम से कूदने की चिंता नहीं करता।

सामान्य स्थिति में, यदि आप स्मृति से बाहर हो जाते हैं, तो प्रोग्राम को पहले से ही असुरक्षित समस्याएं होती हैं जब तक कि इसे विशेष रूप से एक सीमित पदचिह्न (एम्बेडेड सिस्टम) में हमेशा चलाने के लिए डिज़ाइन नहीं किया जाता है - उस स्थिति में आपको सभी के बारे में परवाह करना होगा इन मामलों में।

यदि यह आपके लिए लागू होता है, तो आपके पास एक लंबी कोड समीक्षा और आपके आगे की चक्र को आगे बढ़ाया जा सकता है। मेरा अनुमान है कि यद्यपि आप यहां अपनी टीम के अभ्यास का पालन करना ठीक है।

जैसा कि अन्य ने इंगित किया है, कच्चे पॉइंटर्स को स्टोर करने के लिए vector का उपयोग करके अपनी समस्याएं हैं, और इस साइट पर और अन्य उत्तरों में सामग्री की एक संपत्ति है जो आपको एक सुरक्षित पैटर्न पर निर्देशित करने के लिए है।

+0

यह मतलब ओपी की क्वेरी – Chubsdad

+0

@Chubsdad जवाब नहीं देता था - सवाल टैग है 'अपवाद-सुरक्षित' है, इसलिए मुझे लगता है कि यह प्रासंगिक है। सुझाए गए फिक्स सभी 'वेक्टर' में कच्चे सूचक उपयोग से बात करते हैं, यह बताए बिना कि 'नया' फेंकने पर क्या होता है। –

+1

'नई Foo' फेंकता है, तो कोई स्मृति आवंटित कर ली। यदि 'वेक्टर' पुनर्वितरण फेंकता है, तो हमने अभी 'नए फू' द्वारा आवंटित स्मृति का पता खो दिया है। और एक वेक्टर पुनर्वितरण स्मृति में "छोटा" होने के बिना असफल हो सकता है, अगर यह बहुत अधिक बढ़ता है या आप स्मृति बहुत खंडित है। –

11

आपका नया तरीका अधिक अपवाद सुरक्षित है, लेकिन ऐसा कोई कारण है कि आप इसे कहीं और नहीं देखते हैं।

पॉइंटर्स के vector पॉइंटर्स के स्वामी ही हैं, यह इंगित करने वाली वस्तुओं के स्वामित्व को व्यक्त नहीं करता है। आप प्रभावी रूप से उस ऑब्जेक्ट को स्वामित्व जारी कर रहे हैं जो स्वामित्व को "इच्छित" नहीं करता है।

अधिकांश लोग स्वामित्व को सही तरीके से व्यक्त करने के लिए vector का vector का उपयोग करेंगे या boost::ptr_vector जैसे कुछ का उपयोग करेंगे। इनमें से कोई भी मतलब है कि आपको स्पष्ट रूप से delete ऑब्जेक्ट्स की आवश्यकता नहीं है जिनके पॉइंटर्स आप संग्रहीत कर रहे हैं जो त्रुटि प्रवण है और कार्यक्रम में अन्य बिंदुओं पर संभावित रूप से अपवाद 'खतरनाक' है।

संपादित करें: आपको अभी भी ptr_vector में सम्मिलन के साथ बहुत सावधान रहना होगा। दुर्भाग्य से, push_back कच्चे सूचक को लेने से मजबूत गारंटी मिलती है जिसका अर्थ है कि या तो सम्मिलन सफल होता है या (प्रभावी रूप से) कुछ भी नहीं होता है, इसलिए पारित वस्तु न तो ली जाती है और न ही नष्ट हो जाती है। मूल्य द्वारा एक स्मार्ट पॉइंटर ले जाने वाला संस्करण दृढ़ता से गारंटीकृत संस्करण को कॉल करने से पहले .release() पर कॉल करने के रूप में परिभाषित किया गया है जिसका प्रभावी ढंग से अर्थ है कि यह रिसाव कर सकता है।

एक साथ shared_ptr के vector का उपयोग make_shared साथ बहुत सही ढंग से उपयोग करने के लिए आसान है।

+1

"कॉलिंग .release() के रूप में परिभाषित किया गया है" - यह एक अपमान है। यही है ना –

+1

@ स्टेव: सहमत। गैर-'const' संदर्भ द्वारा 'auto_ptr' लेने के लिए और स्वामित्व सफलतापूर्वक स्थानांतरित होने के बाद ही' रिलीज 'करने के लिए यह अधिक समझदार होगा (मेरे लिए)। –

+0

अच्छा लगता है, 'shared_ptr (auto_ptr)' कन्स्ट्रक्टर के समान। इस उपयोग के लिए, मैं इसे 'shared_ptr (T *)' कन्स्ट्रक्टर के समतुल्य मूल्य के आधार पर ले जाने और इसे रिलीज़ करने या नष्ट करने के लिए भी व्यवस्थित करता हूं लेकिन एक auto_ptr पैरामीटर की सूचक सामग्री पर लागू होता है। –

3

यह करने के लिए पसंदीदा तरीका उदाहरण के लिए, स्मार्ट संकेत के एक कंटेनर का उपयोग कर, एक std::vector<std::shared_ptr<Foo> > या एक std::vector<std::unique_ptr<Foo> > (shared_ptr रूप में अच्छी तरह बूस्ट और सी ++ TR1 में पाया जा सकता है, std::unique_ptr प्रभावी रूप से C++ 0x तक ही सीमित है) ।

एक अन्य विकल्प के लिए एक कंटेनर है कि, गतिशील वस्तुओं का मालिक है उपयोग करने के लिए है बूस्ट सूचक कंटेनर पुस्तकालय द्वारा प्रदान की उन कंटेनरों की तरह।

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