2010-10-25 13 views
10
SomeObj<unsigned int>* Buffer; 
char* BufferPtr = MemoryManager::giveMeSomeBytes(resX*resY*sizeof(SomeObj<unsigned int>)); 
Buffer = new(BufferPtr) SomeObj<unsigned int>[resX*resY]; 

जब मैं डीबगर के साथ इन पंक्तियों से आगे बढ़ने के लिए, यह मेरे लिए मान दिखाता है चर बफर और BufferPtr:नियुक्ति नया + सरणी + संरेखण

BufferPtr: 0x0d7f004c 
Buffer: 0x0d7f0050 

मैं सच में समझ में नहीं आता क्यों उन मूल्यों भिन्न होते हैं। जिस तरह से मैं इसे समझता हूं, प्लेसमेंट को आवंटित स्मृति पर वेर डिफॉल्ट कन्स्ट्रक्टर का उपयोग करके सरणी तत्वों को प्रारंभ करने के लिए 'बफरप्रेट' पते से शुरू होने वाली मेमोरी का उपयोग करना चाहिए और सरणी में पहले तत्व के पहले बाइट में पॉइंटर वापस करना चाहिए, जो होना चाहिए प्लेसमेंट नए ऑपरेटर को पास के रूप में बिल्कुल वही बाइट।

क्या मुझे कुछ गलत समझ आया या कोई मुझे बता सकता है कि मूल्य अलग क्यों हैं?

धन्यवाद!

// संपादित करें: ठीक है - मैं इस मुद्दे को आगे की जांच की और मिल गया भ्रामक परिणाम:

int size = sizeof(matth_ptr<int>); 

    char* testPtr1 = (char*)malloc(a_resX*a_resY*sizeof(int)); 
    int* test1 = new(testPtr1) int[a_resX*a_resY]; 

    char* testPtr2 = mmgr::requestMemory(a_resX*a_resY*sizeof(int)); 
    int* test2 = new(testPtr2) int[a_resX*a_resY]; 

    char* testPtr3 = (char*)malloc(a_resX*a_resY*sizeof(matth_ptr<int>)); 
    matth_ptr<int>* test3 = new(testPtr3)matth_ptr<int>[a_resX*a_resY]; 

    char* testPtr4 = mmgr::requestMemory(a_resX*a_resY*sizeof(matth_ptr<int>)); 
    matth_ptr<int>* test4 = new(testPtr4)matth_ptr<int>[a_resX*a_resY]; 

डिबगर मुझे मेरे चर के लिए निम्न मान देता है:

size: 4 

testPtr1:0x05100418 
test1: 0x05100418 
testPtr2:0x0da80050 
test2: 0x0da80050 

testPtr3:0x05101458 
test3: 0x0510145c 
testPtr4:0x0da81050 
test4: 0x0da81054 

तो यह स्पष्ट रूप से होना चाहिए मेरे जेनेरिक स्मार्टपॉन्टर क्लास matth_ptr के साथ कुछ करने के लिए है तो यहां यह है:

template <class X> class matth_ptr 
{ 
public: 
    typedef X element_type; 

    matth_ptr(){ 
     memoryOfst = 0xFFFFFFFF; 
    } 

    matth_ptr(X* p) 
    { 
     unsigned char idx = mmgr::getCurrentChunkIdx(); 
     memoryOfst = (int)p-(int)mmgr::getBaseAddress(idx); 
     assert(memoryOfst<=0x00FFFFFF || p==0);//NULL pointer is not yet handled 
     chunkIdx = idx; 
    } 
    ~matth_ptr()    {} 
    X& operator*()    {return *((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));} 
    X* operator->()    {return ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));} 
    X* get()     {return ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));} 


    template<typename T> 
    matth_ptr(const matth_ptr<T>& other) {memoryOfst=other.memoryOfst;}//put these two operators into the private part in order to prevent copying of the smartpointers 
    template<typename T> 
    matth_ptr& operator=(const matth_ptr<T>& other) {memoryOfst = other.memoryOfst; return *this;} 
    template<typename T> 
    friend class matth_ptr; 
private: 

    union //4GB adressable in chunks of 16 MB 
    { 
     struct{ 
      unsigned char padding[3]; //3 bytes padding 
      unsigned char chunkIdx; //8 bit chunk index 
     }; 
     unsigned int memoryOfst; //24bit address ofst 
    }; 

}; 

क्या कोई मुझे बता सकता है कि क्या हो रहा है? धन्यवाद!

+0

मेरे सिर के ऊपर से, संरेखण या VTable स्थान हो सकता है। –

+0

क्या इसका मतलब यह है कि प्लेसमेंट नया ऑब्जेक्ट को उच्च मेमोरी एड्रेस पर बनाता है अगर उसे पास किए गए पते के संरेखण को पसंद नहीं है? – Mat

+0

मुझे संदेह होगा, कुछ निश्चित रूप से नहीं जानते हैं। परीक्षण करने का एक तरीका यह देखना होगा कि यह चयनित मेमोरी लोकेशन पर होता है (यानी एक गठबंधन पता देने के लिए बल दें ISomeBytes)। –

उत्तर

5

आप new ऑपरेटर के सरणी संस्करण का उपयोग कर रहे हैं जो आपके कार्यान्वयन में स्मृति आवंटन के पहले कुछ बाइट्स में सरणी आकार के बारे में जानकारी संग्रहीत कर रहा है।

+0

पर समस्या नहीं हो सकता है और जब नए ऑपरेटर का सरणी संस्करण उन बाइट्स को संग्रहीत करता है और यह कब नहीं कर रहा है ? कृपया मूल प्रश्न में मेरा विस्तारित परीक्षण देखें। यह पता चला है कि 'int' प्रकार के साथ पता नहीं है, लेकिन मेरी अपनी वस्तु के साथ यह है। – Mat

+0

चाहे सरणी आकार संग्रहीत किया गया हो, इस पर निर्भर करता है कि ऑब्जेक्ट प्रकार में विनाशक है, क्योंकि हटाएं [] ऑपरेटर को प्रत्येक ऑब्जेक्ट के लिए विनाशक को कॉल करना होगा। – Timo

+0

तो - एक विनाशक रखने वाली वस्तुओं के लिए वास्तव में परेशानियों में भाग लेने के लिए 4 और एक्स्ट्राबाइट आवंटित करना पड़ता है? नियुक्ति के साथ सरणी आवंटन पर चर्चा करने वाले ट्यूटोरियल नए का उल्लेख क्यों नहीं करते? मुझे महत्वपूर्ण लगता है ... – Mat

13

सरणी पर नए प्लेसमेंट से सावधान रहें। अनुभाग 5.3.4.12 करने के लिए वर्तमान मानक नज़र में, आप इस मिल जाएगा:

new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f) 

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

18.4.1.3.4 को भी देखें जहां यह कहता है कि प्लेसमेंट नया ऑपरेटर बस प्रदान किए गए पॉइंटर को वापस देता है। यह स्पष्ट रूप से अपेक्षित हिस्सा है।

5.3.4.12 के आधार पर, क्योंकि ऑफसेट प्रत्येक सरणी के प्रत्येक आमंत्रण के लिए अलग हो सकता है, मानक मूल रूप से इसका मतलब है कि आवश्यक आकार की सटीक मात्रा आवंटित करने का कोई तरीका नहीं है। व्यावहारिक रूप से मूल्य शायद स्थिर है और आप इसे आवंटन में जोड़ सकते हैं, लेकिन उसकी राशि प्रति प्लेटफॉर्म बदल सकती है, और फिर, मानक के रूप में प्रत्येक आमंत्रण के रूप में।

+11

इसलिए मूल रूप से इसका मतलब है - मानक के संबंध में - सरणी पर नया प्लेसमेंट उपयोगी नहीं है – Mat

+0

इन सटीक आकार के प्री-आवंटित सरणी की शर्तें: हां। याद रखें कि आप अभी भी एक कस्टम प्लेसमेंट आवंटक बना सकते हैं जो स्मृति के बड़े ब्लॉक पर एक गतिशील आवंटक की तरह काम करता है। –

+0

ध्यान रखें कि 'ऑपरेटर नया [] (आकार (टी) * 5 + वाई, 2, एफ) 'एक ** उपयोगकर्ता परिभाषित प्लेसमेंट एलोक्शन फ़ंक्शन ** है, जबकि' ऑपरेटर नया [] (आकार (टी) * 5, पीआरटी) 'एक ** गैर-आवंटन प्लेसमेंट आवंटन समारोह ** है। जो आप यहां देखते हैं वह एक और एफ ** के ऊपर है जो "समिति" द्वारा लापरवाही सामान्यीकरण के परिणामस्वरूप होता है। मुझे आशा है कि यह 2020 से बाद में साफ़ नहीं हो जाएगा। – bit2shift

1

जैसा कि अन्य ने कहा है, यह आपके सी ++ कार्यान्वयन के कारण है जिसे आप सरणी प्लेसमेंट में पास किए गए बफर की शुरुआत में सरणी के आकार को संग्रहीत करते हैं।

इसके लिए एक आसान फिक्स बस अपने सरणी सूचक को बफर में असाइन करना है, फिर सरणी पर लूप करें और प्रत्येक ऑब्जेक्ट को बफर में बनाने के लिए नियमित (गैर-सरणी) प्लेसमेंट का उपयोग करें।

2

@Mat, यह वास्तव में एक अच्छा सवाल है। जब मैंने प्लेसमेंट का उपयोग किया है [], मुझे स्टोरेज को हटाने में परेशानी हुई है।यहां तक ​​कि यदि मैं अपना खुद का सममित प्लेसमेंट हटाता हूं [], सूचक पता जैसा नहीं है जैसा कि मेरे अपने प्लेसमेंट द्वारा वापस किया गया था []। यह नियुक्ति में सुझाव दिया गया है, जैसा कि प्लेसमेंट नया [] पूरी तरह से बेकार बनाता है।

जोनाथन @ द्वारा दिया गया एकमात्र समाधान सुझाया गया था: प्लेसमेंट के बजाय [], सरणी के प्रत्येक तत्व पर प्लेसमेंट नई (गैर-सरणी) का उपयोग करें। यह मेरे लिए ठीक है क्योंकि मैं खुद को आकार संग्रहित करता हूं। समस्या यह है कि मुझे तत्वों के लिए पॉइंटर संरेखण के बारे में चिंता करने की ज़रूरत है, जो नया [] मेरे लिए करना है।

+1

प्लेसमेंट डिलीट ऑपरेटर जैसी कोई चीज़ नहीं है। नियुक्ति हटाएं * फ़ंक्शन * को कन्स्ट्रक्टर प्लेसमेंट के नए ऑपरेटर के अंदर फेंकने पर कॉल किया जाता है, और यह बिल्कुल कुछ भी नहीं करता है। कृपया सलाह दीजिये, 'शून्य *' प्लेसमेंट नए ऑपरेटरों का मतलब किसी दिए गए मेमोरी क्षेत्र में ऑब्जेक्ट्स बनाने के लिए है, ढेर से स्मृति आवंटित नहीं करना है। इस प्रकार, आप * प्लेसमेंट नई सरणी के साथ बनाए गए क्षेत्र पर ऑपरेटर 'डिलीट' या 'हटाएं []' का उपयोग नहीं कर सकते हैं, आपको सरणी लंबाई (परिचित लगता है?) और सरणी के माध्यम से लूप रखना होगा और प्रत्येक विनाशक को कॉल करना होगा। – bit2shift

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