2009-11-27 7 views
9

मैं अपने स्वयं के आवंटकों के साथ नए/हटाए जाने की कोशिश कर रहा हूं। तो, प्लेसमेंट को ओवरराइड करना और हटाएं - उससे काफी खुश। कुछ इस तरह दिखता ...वैश्विक "प्लेसमेंट" हटाएं []

सी ++ भाषा को स्पष्ट करता प्लेसमेंट को हटा के लिए, आप स्पष्ट रूप से ~ dtor कॉल करने के लिए है,। कंपाइलर यह आपके लिए नहीं करता है। चाहे यह एक टेम्पलेटेड ऑपरेटर है या दिखाए गए स्पष्ट कार्य है।

देखें http://www2.research.att.com/~bs/bs_faq2.html#placement-delete

समस्या है - मैं इस सरणी के लिए काम करने को नष्ट [] मिल सकता है? मुझे पता है कि मुझे सरणी के माध्यम से पुन: प्रयास करने की आवश्यकता है और खुद को ~ dtor कॉल करें। इसलिए मैं सरणी के आकार,

स्पष्टता

मैं इस जानकारी को संग्रहीत या ब्लॉक आकार से यह अनुमान लगा सकते हैं के लिए संपादित की जरूरत है। हालांकि, समस्या यह है कि संकलक (एमएसवीसी v9) अलग-अलग चीजें करता है अगर मैं बिना किसी के मुकाबले विनाशकों के साथ वस्तुओं की एक सरणी आवंटित कर रहा हूं, यानी यदि कोई डॉटोर है तो यह अतिरिक्त 4 बाइट आवंटित करेगा। ऐसा इसलिए है क्योंकि मानक हटाने के लिए कंपाइलर [] को एक ही काम करने की आवश्यकता है और हटाए जाने के लिए उपयुक्त कोड जोड़ सकते हैं []।

हालांकि मेरे अपने "प्लेसमेंट" में हटाएं [] मेरे पास यह जानने का कोई तरीका नहीं है कि संकलक ने संकलन समय पर सुरक्षित रूप से क्या किया या निर्धारित किया है कि कक्षा में एक डॉटर है।

उदा।

char buf[ 1000 ]; 

MyClass* pA = new(buf) MyClass[ 5 ]; 

यहाँ पीए के मूल्य 4 BUF है यदि वहां मौजूद ~ MyClass() और आवंटित स्मृति की मात्रा sizeof (MyClass) है * 5 + 4. हालांकि अगर कोई dtor तो पीए == buf है और आवंटित स्मृति की मात्रा आकार (MyClass) * 5.

तो मेरा सवाल यह है - क्या यह व्यवहार एक भाषा मानक और कंपाइलर्स में संगत है या यह एमएसवीसी के लिए विशिष्ट है? क्या किसी और को इस समस्या का अच्छा समाधान मिला है? मुझे लगता है कि एकमात्र विकल्प नया [] का उपयोग नहीं करना है और खुद को निर्माण करना ठीक है जो कि ठीक है लेकिन फिर कॉलिंग कोड सिंटैक्स थोड़ा असामान्य है .. या प्रत्येक वर्ग को विनाशक होने के लिए मजबूर करता है।

+1

आप "प्लेसमेंट को हटा" ओवरराइड नहीं करें यहाँ। –

+0

अगर alignof (MyClass) == 8, मैं शर्त लगाता हूं कि pa _not_ buf + 4. – Bahbar

+0

सत्य है, लेकिन मुझे लगता है कि मैं आकार प्राप्त कर सकता हूं, मुझे अभी भी पता नहीं है कि कंपाइलर ने इसे रखा है या नहीं। यदि MyClass में कोई dtor pA == buf नहीं है। – Gwaredd

उत्तर

3

लघु जवाब:

इस प्रयोग के लिए कोई सीधा समर्थन नहीं है। यदि आप एक अलग हस्ताक्षर के साथ नया अधिभारित करते हैं, तो संकलक इसे नए अधिभार (नए प्लेसमेंट नहीं) मानता है और अपना स्वयं का बुक-रखरखाव कोड जोड़ता है। कंपाइलर को कहने के लिए कोई रास्ता नहीं है (मुझे मिल सकता है) "अपनी पुस्तक-रखरखाव को खोलें, और इस हस्ताक्षर से मेल खाने वाले मेरे डिलीट ओवरलोड को कॉल करें" - यह केवल void operator delete(void* p) या void operator delete[](void* p) पर कॉल करते समय पुस्तक-पालन को अनदेखा करने के लिए कोड डालेगा।

यदि आप नए हस्ताक्षर के साथ नए ओवरराइड करते हैं, तो संकलक आपको नए के दौरान अपवादों के मामले में मिलान करने वाले हस्ताक्षर के साथ एक डिलीट को परिभाषित करना पसंद करता है - यह एकमात्र समय होता है।

इस बात में कोई प्लेसमेंट हटा नहीं है कि यह कॉल करने योग्य नहीं है, लेकिन अपवादों (कुछ भी करने के लिए) में यह परिभाषित नहीं किया गया है।

लांग जवाब:

इस विषय में कुछ रोचक अंक को जन्म देती है:

  1. क्या, वास्तव में, void* operator new[](size_t sz, Allocator* a) अधिभार करता है?
  2. क्या वहां है, या "प्लेसमेंट डिलीट" नहीं है।
  3. कोई व्यक्ति void operator delete[](void* p, Allocator* a) कैसे आमंत्रित करता है, इस तरह से संकलक अपनी पुस्तक-रखरखाव अंतिम रूप देता है?

प्वाइंट 1: नियुक्ति को ओवरलोड करने के बारे में बहुत कुछ बात। यह देखते हुए कि संकलक पुस्तक रखने के कोड को सम्मिलित कर रहा है, यह राय होना चाहिए कि void* operator new[](size_t sz, Allocator* a) एक ओवरलोड (गैर-प्लेसमेंट) नया घोषित करता है। यह नियुक्ति के लिए पुस्तक-पालन कोड कभी भी नहीं डालेगा, क्योंकि प्लेसमेंट का बिंदु नया है कि आप इसे स्वयं संभालने वाले हैं।

प्वाइंट 2: आरई। "प्लेसमेंट डिलीट जैसी कोई चीज़ नहीं है", आपको ऐसा कुछ मिल जाएगा जो इस तरह से दिखता है (और इस तरह टिप्पणी करता है) उदा। वीएस 2 के 8 नया हेडर। यह केवल उन मामलों में उपयोग किया जाता है जहां नियुक्ति के दौरान अपवाद होता है। हालांकि यह सच साबित होता है कि आप सार्थक तरीके से नियुक्ति हटा नहीं सकते हैं।

प्वाइंट 3: यदि कोई रास्ता है, तो मुझे यह नहीं मिल रहा है। यह समस्या का दिल है।

समस्या के व्यावहारिक समाधान के संदर्भ में, यह एक बस्ट प्रतीत होता है।

उदाहरण के लिए

:

//intention: user provides memory pool, compiler works out how many bytes required 
//and does its own book-keeping, as it would for a void* operator new[](size_t sz) overload 
//calling syntax: CObj* pMyArr = new(pMyMemPool) CObj[20]; 
void* operator new[](size_t sz, IAlloc* pMemPool) 
{ return pMemPool->alloc(sz); } 

//problem: don't know the syntax to call this! 
//e.g. delete[](pMyMemPool) pMyArr is syntax error 
void* operator delete[](void* p, IAlloc* pMemPool) 
{ return pMemPool->free(p); } 

//nb: can be called as operator delete(pMyArr, pMyMemPool); 
//but compiler does not finish its book-keeping or call dtors for you in that case. 

ध्यान दें कि यह विषमता नया गैर सरणी के लिए मौजूद है & भी हटा सकते हैं। हालांकि, क्योंकि (अनुभवजन्य) प्रश्न में संकलक कोई अतिरिक्त पुस्तक-पालन नहीं करता है, इसे सभी को काम करने के लिए बनाया जा सकता है। दोबारा, अगर यह मानक में निहित है तो मुझे नहीं पता।

void* operator new(size_t sz, IAlloc* pMemPool) 
    { return pMemPool->alloc(sz); } 


//don't know syntax to get this called by compiler! 
    void operator delete(void* p, IAlloc* pMemPool) 
    { pMemPool->free(p); } 

    //is ok though, can work around 
    template<class T> void tdelete(void* p, IAlloc* pMemPool) 
    { 
    //no problems, p points straight at object 
    p->~T(); 

    operator delete(p, pMemPool); 
    //OR just 
    pMemPool->free(p); 
    } 

    void* operator new[](size_t sz, IAlloc* pMemPool) 
    { return pMemPool->alloc(sz); } 

    //again, don't know syntax to end up here. 
    void operator delete[](void* p, IAlloc* pMemPool) 
    { pMemPool->free(p); } 

    //can't work around this time! 
    template<class T> void tarrdelete(void* p, IAlloc* pMemPool) 
    { 
    //problem 1: how many to dtor? 
    for(int i=0; i<???; ++i) 
    { reinterpret_cast<T*>(p+i)->~T(); } 
    //problem 2: p points at first element in array. this is not always the address 
    //that was allocated originally. 
    pMemPool->free(?); 

    //as already explained by OP, no way to tell if p is address allocated or 
    //address allocated+4 bytes, or something else altogether. this means no way to know what address to un-alloc or how many dtors to call. 

    } 

अंत में, मैं obvs राज्य होगा।

//sz may include extra for book-keeping 
void* operator new[](size_t sz) 
{ return GAlloc->alloc(sz); } 

//works fine, compiler handled book-keeping and p is the pointer you allocated 
void operator delete[](void* p) 
{ return GAlloc->free(p); } 

सारांश: वहाँ वाक्य रचना कि संकलक "जादू" सक्षम के साथ, एक विस्तारित पैरामीटर सूची के साथ हटाना की एक अधिभार के लिए कॉल की अनुमति देगा है - विस्तारित पैरामीटर सूची के बिना भार के काम करते हैं। या, ओवरराइड द्वारा प्लेसमेंट नए में पैरामीटर जोड़ने का कोई तरीका है?

संदिग्ध जवाब: नहीं

उपप्रमेय: आप 6 में निर्मित पूरी स्वतंत्रता के साथ नए हस्ताक्षर से दूर नहीं कर सकते। ऐसा करने के परिणामस्वरूप संकलक उत्पन्न पुस्तक-रखरखाव के साथ नए ओवरलोड में परिणाम मिलता है, लेकिन बुक-रख-रखाव से बाहर निकलने के लिए संबंधित डिलीट तक पहुंच नहीं होती है।

कैविट: आप अंतर्निहित हस्ताक्षर से भटक सकते हैं, लेकिन केवल कोड इंजेक्ट करने के लिए आपको हटाने (उदा। उपकरण) पर फिर से संभालने की आवश्यकता नहीं है। यदि आप आवंटन के लिए void* operator new(size_t s) संस्करण तक पहुंचते हैं, तो हटाएं अभी भी सामान्य के रूप में काम करेंगे।

(वास्तव में से कुछ बयान डीबगर में प्रयोगों से तैयार कर रहे हैं और केवल MSVC8 (Cl9) के लिए आवेदन कर सकते हैं। ओपी मेरे बगल में डेस्क पर बैठता है।)

+0

तो मैं मुसीबत में हूँ;) http://groups.google.co.uk/group/comp.lang.c++/browse_thread/thread/80753a80fa705077/f7928615131dab9d?hl=en&ie=UTF-8&oe=utf-8&q= प्लेसमेंट + डिलीट + समूह: comp.lang.c% 2 बी% 2 बी – Gwaredd

+0

स्पष्ट रूप से यह "कार्यान्वयन परिभाषित" है, 33.4 और 33.5 देखें ... http://groups.google.co.uk/group/comp।जवाब/browse_thread/धागा/c8dee7162c40b348/38af85c3d71454d0 hl = hi & यानी = UTF-8 और ँ = UTF-8 & q = नियुक्ति + हटाना + नाशक + सरणी + समूह:? comp.lang.c% 2 बी 2 बी% – Gwaredd

0

आप अपने संभाजक में सूचक देखो अपने बहीखाता से आकार का पता लगाना और तत्वों की संख्या की गणना sizeof टी

4

का उपयोग करते समय संदेह में विशेषज्ञ करने के लिए जा सकते हैं:

http://www.stroustrup.com/bs_faq2.html#placement-delete

लेकिन बाद में हम उन वस्तुओं को सही ढंग से कैसे हटा सकते हैं? प्लेसमेंट नए से मेल खाने के लिए कोई अंतर्निहित "प्लेसमेंट डिलीट" नहीं है कि यह सुनिश्चित करने का कोई सामान्य तरीका नहीं है कि इसका सही उपयोग किया जाएगा। सी ++ टाइप सिस्टम में कुछ भी हमें उस पी 1 अंक को एरिना ए 1 में आवंटित ऑब्जेक्ट को कम करने की अनुमति देता है। किसी भी एक्स आवंटित किसी भी एक्स को पॉइंटर को पी 1 को असाइन किया जा सकता है।

शेष लिंक स्थिति का समाधान करने के तरीके पर वर्णन करता है।

+0

हां मैंने लिंक पढ़ा - यह सवाल संख्या जैसा ही है? यह सरणी के लिए कोई समाधान प्रदान नहीं करता है, समस्या यह है कि संकुचित करने का कोई तरीका नहीं है कि संकलक ने अतिरिक्त स्थान आवंटित किया है या नहीं, इसलिए मुझे नहीं पता कि मेरा वास्तविक सरणी कहां से शुरू होता है। यह एक एमएसवीसी विशिष्ट चीज़ भी हो सकता है ... – Gwaredd

+0

@Gwaredd, मैं आपको लिंक पर नजदीक देखने की कोशिश कर रहा था, जहां यह कहता है कि प्लेसमेंट हटाने जैसी कोई चीज़ नहीं है और यदि आप ऐसा करना चाहते हैं आप करने की कोशिश कर रहे हैं, आपको आकार को ट्रैक करने की आवश्यकता होगी। :) – chollida

+0

हाँ, मैंने समस्या को बहुत स्पष्ट नहीं किया: o मुद्दा यह है कि संकलक एक डीटीओ की उपस्थिति के आधार पर नए [] के लिए दो अलग-अलग चीजें करता है। बस सोच रहा है कि किसी के पास समाधान है :) – Gwaredd

1

"प्लेसमेंट डिलीट" जैसी कोई शब्दावली नहीं है। जैसा कि आपने कहा था, यदि आप प्लेसमेंट के साथ कुछ आवंटित करते हैं, तो जब इसे हटाने का समय आता है तो आपको विनाशक को मैन्युअल रूप से आवेदक करने की आवश्यकता होती है और फिर प्लेसमेंट के लिए आवंटित वास्तविक मेमोरी बफर का भी ख्याल रखना पड़ता है।

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

तो, उदाहरण के लिए, यदि आप कुछ बफर, char buf[1000] तरह का आवंटन, और फिर आप प्लेसमेंट बफर में Foo ऑब्जेक्ट की श्रृंखला के निर्माण के लिए नए प्रयोग करते हैं, जहां सी ++ सरणी आकार जानकारी स्टोर करने के लिए माना जाता है? यह इसे आपके बफर में स्टोर नहीं करेगा, क्योंकि यह नहीं जानता कि आप उस बफर के साथ क्या करना चाहते हैं। इसलिए प्रत्येक आवंटन के आकार को रिकॉर्ड करने के लिए आप पर निर्भर है, और फिर उचित रूप से जोड़े को हटा दें।

+0

मैंने इस सवाल में खुद को स्पष्ट रूप से समझाया नहीं। मुझे पता है कि मुझे विनाशकों को मैन्युअल रूप से कॉल करने और इसे संभव बनाने के लिए जो भी जानकारी चाहिए, उसे स्टोर करने की आवश्यकता है। हालांकि, संकलक मेरे लिए प्रारंभिक कोड उत्पन्न करता है। सरणी के मामले में [] संकलक (एमएसवीसी 9) कक्षा में एक डॉटर है या नहीं, अलग कोड उत्पन्न करता है। सामान्य हटाने के लिए [] मुझे लगता है कि संकलक उचित विनाश कोड उत्पन्न करता है, हालांकि प्लेसमेंट हटाने के लिए यह नहीं है (सी ++ स्पेक के अनुसार) और मेरे डिलीट में [] मेरे पास यह जानने का कोई तरीका नहीं है कि सामान्य मामले में कंपाइलर ने क्या किया। .. जब तक मैं कुछ याद नहीं कर रहा हूँ? – Gwaredd

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