2014-10-23 9 views
10
रिहा

चलें कहते हैं कि मैं एक एसटीडी वेक्टर में डेटा प्राप्त करने के लिए एक समारोह है बिना std :: वेक्टर नष्ट:स्मृति

void getData(std::vector<int> &toBeFilled) { 
    // Push data into "toBeFilled" 
} 

अब मैं एक और समारोह के लिए इस डेटा भेजना चाहते हैं, कि डेटा समाप्त होने पर मुक्त कर देना चाहिए :

void useData(int* data) 
{ 
    // Do something with the data... 
    delete[] data; 
} 

दोनों कार्य (getData और useData) तय किए गए हैं और इन्हें बदला नहीं जा सकता है।

{ 
    std::vector<int> data; 
    getData(data); 
    int *heapData = new int[data.size()]; 
    memcpy(heapData, data.data(), data.size()*sizeof(int)); 
    useData(heapData); 
    data.clear(); 
} 

हालांकि, इस memcpy ऑपरेशन के बाद से डेटा ढेर पर पहले से ही है, महंगा है और वास्तव में आवश्यक नहीं है: जब डेटा एक बार को कॉपी यह ठीक काम करता है। क्या सीडी वेक्टर द्वारा आवंटित डेटा को सीधे निकालना और उपयोग करना संभव है? (स्यूडोकोड) की तरह कुछ:

{ 
    std::vector<int> data; 
    getData(data); 
    useData(data.data()); 
    data.clearNoDelete(); 
} 

संपादित करें:

उदाहरण शायद बहुत ज्यादा मतलब नहीं है, क्योंकि यह संभव है बस useData को समारोह कॉल के बाद वेक्टर मुक्त करने के लिए। हालांकि, वास्तविक कोड में, useData नहीं एक समारोह लेकिन एक वर्ग है कि डेटा प्राप्त करता है, और इस वर्ग के वेक्टर से अधिक समय रहता है ...

+4

मुझे डर है कि आप ऐसा नहीं कर सकते हैं। किसी भी तरह से वेक्टर को अपनी याददाश्त के बिना खाली किया जा सकता है ... – jpo38

+24

यह किस तरह का पागल एपीआई है ?! सुनिश्चित करने के लिए –

+1

@LightnessRacesinOrbit +1। और जनवरी, आपको पता नहीं है कि डेटा ढेर पर है। मानक केवल अनिवार्य है कि यह संगत और यादृच्छिक-पहुंच योग्य (और कुछ अन्य चीजें) है। 'Std :: string' की तरह, प्लेसमेंट-न्यू के लिए एक उचित छोटी वस्तु-स्थिर बफर के साथ एक छोटे-आइटम-गिनती वेक्टर के लिए यह अनदेखा नहीं किया जाएगा, जब पृष्ठ को बहुत छोटा माना जाता है तो पूरी तरह से गतिशील होता है। इस तरह के एक कार्यान्वयन आपके द्वारा उपयोग किए जाने वाले उपयोग के अनुपालन में * गंभीर रूप से * उड़ाएगा। – WhozCraig

उत्तर

25

सं

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

वेक्टर हमेशा आवंटित स्मृति को आवंटित करेगा और इसमें मौजूद तत्वों को सुरक्षित रूप से नष्ट कर देगा। यह इसके गारंटीकृत अनुबंध का हिस्सा है और आप इसे बंद नहीं कर सकते हैं।

आप यदि आप उनमें से स्वामित्व ... या कदम प्रत्येक तत्व बाहर अपने खुद के कंटेनर में लेना चाहते हैं डेटा की एक प्रतिलिपि बनाने के लिए है। या पहले स्थान पर अपने new[] से शुरू करें (यूघ) हालांकि आप इसे कम से कम कुछ कक्षा में लपेट सकते हैं जो std::vector की नकल करता है और गैर-स्वामित्व बन जाता है।

+0

हम्म ... हालांकि शायद "स्वैप (डेटा, हेपडाटा)" या इसी तरह के कुछ तरीके हैं ... –

+2

* "वेक्टर हमेशा आवंटित स्मृति को आवंटित करेगा और इसमें मौजूद तत्वों को सुरक्षित रूप से नष्ट कर देगा ... आप इसे बंद नहीं कर सकते हैं। "* - आप मूल 'वेक्टर' पर 'नया' खाली 'वेक्टर ' प्लेसमेंट कर सकते हैं जैसे विनाशक - जब रन - पहले आवंटन के बारे में नहीं जानता है; यहां वास्तविक समस्या यह है कि डिफ़ॉल्ट आवंटक 'new []' का उपयोग नहीं करता है, भले ही उसने '.ata()' समान मान नहीं दिया हो, इसलिए '.data()' मान पर हटाएं [] ' असुरक्षित है, और उन सभी को ठीक करने के लिए एक कस्टम आवंटक लिखना जिनमें अपरिहार्य अक्षमताएं शामिल हैं + 'reinterpret_cast' 'getData()' को कॉल करने के लिए। –

+4

@ टोनीडी: यह वक्र है यूबी। मैं इसे एक झूठा समाधान मानता हूं। –

7

यहाँ एक भयानक हैक जो आप क्या जरूरत है ऐसा करने की अनुमति चाहिए है, लेकिन यह सबसे सरल बात यह कर सकते हैं कर अपरिभाषित व्यवहार पर निर्भर करता है।

template <class T> 
struct CheatingAllocator : std::allocator<T> 
{ 
    using typename std::allocator<T>::pointer; 
    using typename std::allocator<T>::size_type; 

    void deallocate(pointer p, size_type n) { /* no-op */ } 

    // Do not add ANY data members!! 
}; 


{ 
    std::vector<int, CheatingAllocator<int>> data; 
    getData(reinterpret_cast<std::vector<int>&>(data)); // type pun, `getData()` will use std::allocator internally 
    useData(data.data()); 
    // data actually uses your own allocator, so it will not deallocate anything 
} 

ध्यान दें कि यह के रूप में hacky और असुरक्षित हैक्स जाना के रूप में बताया गया है: कि आप अपना खुद संभाजक जो लेआउट संगत std::allocator और टाइप-यमक वेक्टर के साथ है बनाने के लिए है। यह मेमोरी लेआउट पर निर्भर नहीं है और यह new[] का उपयोग allocate फ़ंक्शन के अंदर करता है। मैं इसे उत्पादन कोड में खुद का उपयोग नहीं करता, लेकिन मेरा मानना ​​है कि यह एक (हताश) समाधान है।


सही ढंग से टिप्पणी में कहा @TonyD कि std::allocator काफी करने के लिए आंतरिक रूप से नहीं उपयोग new[] संभावना है। इसलिए, उपर्युक्त के अंदर delete[] पर अधिकतर असफल हो जाएगा। वही @ टोनीडी ने reserve() (उम्मीदपूर्वक) getData() के अंदर पुनर्वितरण को रोकने के लिए एक अच्छा बिंदु भी बनाया।तो अद्यतन कोड इस तरह दिखेगा:

template <class T> 
struct CheatingAllocator : std::allocator<T> 
{ 
    using typename std::allocator<T>::pointer; 
    using typename std::allocator<T>::size_type; 

    pointer allocate(size_type n) { return new T[n]; } 

    void deallocate(pointer p, size_type n) { /* no-op */ } 

    // Do not add ANY data members!! 
}; 


{ 
    std::vector<int, CheatingAllocator<int>> data; 
    data.reserve(value_such_that_getData_will_not_need_to_reallocate); 
    getData(reinterpret_cast<std::vector<int>&>(data)); // type pun, `getData()` will use std::allocator internally 
    useData(data.data()); 
    // data actually uses your own allocator, so it will not deallocate anything 
} 
+0

इस (बहुत रचनात्मक) समाधान के लिए बहुत बहुत धन्यवाद: डी लेकिन आप सही हैं, मुझे शायद इसके बजाय किसी प्रकार के बड़े रिफैक्टरिंग के साथ जाना होगा ... –

+0

इसके साथ कुछ समस्याएं हैं ... पहले , यदि 'getData()' 'आकार बदलने 'को ट्रिगर करने के लिए कुछ भी करता है, तो डेटा को नए क्षेत्र में कॉपी करने के बाद निष्क्रिय' deallocate' पुरानी मेमोरी क्षेत्र को रिसाव कर देगा। दूसरा, आवंटकों को 'नया []' , और आपके कस्टम व्यक्ति के उत्तराधिकारी 'आवंटित' समारोह के लिए ई 'हटाया नहीं जा सकता [] '-ed भी हो सकता है भले ही एक ही सूचक' .ata()' द्वारा प्राप्त किया जाए। यदि कस्टम आवंटक 'नया []' स्वयं को आमंत्रित करता है, और '.contruct' और' .destroy' 'को भी नहीं खोलता है, तो मुझे लगता है कि आपको' reinterpret_cast' 'के साथ छोड़ा गया है, जो अनिर्धारित व्यवहार का एकमात्र स्रोत है - बहुत अच्छा। –

+1

@ टोनीडी मुझे लगता है कि वहां बहुत अधिक यूबी है। 'getData()' '' CheatingAllocator 'का आह्वान नहीं करेगा, यह संभवतः 'std :: आवंटक' पर सभी परिचालनों का आह्वान करेगा, क्योंकि यह' std :: vector > पर संचालित होने का मानना ​​है। '। यही कारण है कि मैंने कहा कि यह 'नया []' आंतरिक रूप से 'std :: आवंटन' पर निर्भर करता है (जिसे, 'std' की हेडर-केवल प्रकृति दी गई है, कम से कम सत्यापित किया जा सकता है)। – Angew

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