2010-10-06 18 views
8

इस I need C++ array class template, which is fixed-size, stack-based and doesn't require default constructor उत्तर में मैंने कोड का एक टुकड़ा पोस्ट किया है, जो चार सरणी के साथ प्लेसमेंट नया उपयोग कर रहा है। मेरे लिए, यह बिल्कुल सामान्य है। लेकिन टिप्पणियों के मुताबिक यह कोड गलत है।प्लेसमेंट नया मुद्दा

क्या कोई और विस्तार से समझा सकता है?

विशेष रूप से सरणी के साथ क्या गलत हो सकता है। टिप्पणियों से मैं क्या समझता हूं कि T x[size];char x[size*sizeof(T)]; में फिट नहीं हो सकता है। मुझे विश्वास नहीं है कि यह सच है।

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

मैं बस अधिक से अधिक भ्रमित हूं। मुझे पता है कि संरचनाओं के मामले में संरेखण क्या है। हां, जब आपके पास संरचना होती है तो गुण अलग-अलग ऑफसेट पर शुरू होते हैं तो आप सोच सकते हैं।

ठीक है, अब हम सरणी पर वापस आ गए हैं। आप मुझे बता रहे हैं कि T x[size];char x[size*sizeof(T)]; जैसा ही आकार है, फिर भी मैं टी सरणी के रूप में चार सरणी तक नहीं पहुंच सकता क्योंकि कुछ संरेखण हो सकता है। सरणी के समान आकार होने पर संरेखण कैसे हो सकता है?

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

ठीक मैं अंत में इसे पाने के, यह एक गलत पते पर शुरू हो सकता है।

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

Thx सब लोग, आप पोस्ट :-) ओह, अब यह कुल मेरे मन विस्फोट से उड़ा दिया रोक सकता है। मैंने कभी यह महसूस नहीं किया कि यह संभव था।

+1

आपने टिप्पणियों को गलत समझा। यह * फिट बैठता है, लेकिन चार-सरणी गलत गठबंधन हो सकती है। –

+0

@ स्टेव लेकिन इसका क्या अर्थ है, कृपया समझाएं। चार सरणी की तरह विपरीत क्रम में या अनुक्रमित किया जाएगा। मुझे क्या हो सकता है इसका कुछ उदाहरण दें। मैं केवल संरचनाओं के संदर्भ में और छोटे/बड़े-एंडियन के संदर्भ में संरेखण को समझता हूं। –

+1

@Let_Me_Be: एक स्पष्टीकरण के लिए http://en.wikipedia.org/wiki/Segmentation_fault#Bus_error यहां एक नज़र डालें। –

उत्तर

13

T x[size] सरणी हमेशा size * sizeof(T) बाइट्स में ठीक से फिट हो जाएगी, जिसका अर्थ है कि char buffer[size*sizeof(T)] हमेशा ऐसी सरणी को स्टोर करने के लिए पर्याप्त है।

कि जवाब में समस्या, के रूप में मैं इसे समझ में आया, कि अपने char सरणी होने की गारंटी नहीं है ठीक से प्रकार T की वस्तु के भंडारण के लिए गठबंधन था। केवल malloc -ed/new -ed बफर को किसी भी मानक डेटा प्रकार के छोटे या समान आकार (या मानक डेटा प्रकारों से बना डेटा प्रकार) को स्टोर करने के लिए ठीक से संरेखित करने की गारंटी दी जाती है, लेकिन यदि आप स्पष्ट रूप से char सरणी घोषित करते हैं (स्थानीय के रूप में ऑब्जेक्ट या सदस्य सबोबजेक्ट), ऐसी कोई गारंटी नहीं है।

संरेखण का अर्थ है कि कुछ प्लेटफ़ॉर्म पर यह सख्ती से (या इतनी सख्ती से) आवंटित करने की आवश्यकता नहीं है, कहें, सभी int ऑब्जेक्ट्स, 4-बाइट सीमा पर कहें। जैसे आप ऑब्जेक्ट 0x1000 या 0x1004 पर ऑब्जेक्ट पर रख सकते हैं, लेकिन आप 0x1001 पते पर int ऑब्जेक्ट नहीं डाल सकते हैं। या, अधिक सटीक, आप कर सकते हैं, लेकिन इस स्मृति स्थान को int के ऑब्जेक्ट के रूप में एक्सेस करने के किसी भी प्रयास के परिणामस्वरूप क्रैश हो जाएगा।

जब आप मनमानी char सरणी बनाते हैं, तो संकलक यह नहीं जानता कि आप इसका उपयोग करने की योजना बना रहे हैं। यह उस सरणी को 0x1001 पते पर रखने का निर्णय ले सकता है। उपर्युक्त कारण के लिए, इस तरह के एक असाइन किए गए बफर में int सरणी बनाने का एक निष्पक्ष प्रयास विफल हो जाएगा।

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

उचित संरेखण के लिए की जरूरत कभी कभी मतलब है जब आप एक मनमाना char सरणी में एक int सरणी बनाना चाहते हैं, आप पारीchar सरणी की शुरुआत से एक int सरणी आगे की शुरुआत करने के लिए हो सकता है। उदाहरण के लिए, char सरणी 0x1001 में रहता है, तो आप लेकिन पता 0x1004 (जो सूचकांक 3 के साथ char तत्व है) से अपने निर्माण में जगह int सरणी शुरू करने के लिए कोई विकल्प नहीं है। int सरणी के पूंछ हिस्से को समायोजित करने के लिए, char सरणी size * sizeof(T) का मूल्यांकन करने के मुकाबले 3 बाइट्स बड़ी होनी चाहिए। यही कारण है कि मूल आकार पर्याप्त नहीं हो सकता है।

आम तौर पर, यदि आपके char सरणी किसी भी तरह से गठबंधन नहीं है, तुम सच में size * sizeof(T) + A - 1 बाइट्स की एक सरणी एक गठबंधन को समायोजित करने की आवश्यकता होगी (यानी संभवतः स्थानांतरित कर दिया) प्रकार T की वस्तुओं है कि एक-बाइट सीमा पर गठबंधन किया जाना चाहिए की सरणी ।

+0

"चार सरणी को टाइप टी के ऑब्जेक्ट को संग्रहीत करने के लिए सही ढंग से गठबंधन करने की गारंटी नहीं है" इसका क्या अर्थ है? –

+2

@Let_Me_Be: संक्षेप में - http://en.wikipedia.org/wiki/Data_structure_alignment –

+0

+1 समस्या के स्पष्ट स्पष्टीकरण के साथ उत्कृष्ट उत्तर। – JoshD

0

T को चार से अलग गठबंधन किया जा सकता है।

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

size_t elementCount; 
// padding to get native alignment for 1st element 
T elements[elementCount]; 

तो एक 16 बाइट गठबंधन वस्तु के लिए आवंटन है: नई के माध्यम से आवंटन (IIRC) इस तरह है

size_t elementCount; // 4 
char padding[16 - sizeof(elementCount)]; 
T elements[elementCount]; // naturally aligned 

चार कुछ सिस्टम पर 1 के लिए गठबंधन किया जा सकता है ताकि ... आप देखें कि misalignment और आकार के मुद्दों में फिट कहाँ है। बिल्टिन प्रकारों को उनके dtors बुलाया नहीं है, लेकिन बाकी सब कुछ करता है।

+0

"टी को चार से अलग गठबंधन किया जा सकता है।" इसका क्या मतलब है? –

+0

@Let_Me_Be किसी प्रकार के संरेखण को ऑब्जेक्ट के आकार और सामग्रियों के आधार पर कंपाइलर द्वारा निर्धारित किया जाता है - यह आमतौर पर आपके द्वारा लक्षित प्लेटफ़ॉर्म के लिए एक अच्छी तरह से छुपा कार्यान्वयन विवरण होता है। इसका मतलब है कि सभी वस्तुओं को इस बाइट सीमा पर बनाया गया है। एक char के लिए, (यद्यपि कार्यान्वयन परिभाषित) यह एक (बाइट सीमा) पर रखा जा सकता है (hypothetically)। ऑब्जेक्ट्स/कक्षाओं में आमतौर पर बड़े संरेखण मान होते हैं, जैसे कि 4 - तो इसका मतलब है कि स्टैक पर 'टी' 3 बाइट्स बर्बाद कर सकता है यदि कोई char इससे पहले होता है (उदा। फ़ंक्शन में)। संकलक मानता है कि सभी तर्क प्राकृतिक रूप से पारित/बनाए गए हैं ... – justin

+0

(continud ...) संरेखण। यदि यह ऑब्जेक्ट प्राकृतिक संरेखण पर पारित नहीं किया गया है तो संकलक के पते के लिए धारणाएं आपके प्रोग्राम को असामान्य तरीकों से संचालित करने का कारण बनेंगी क्योंकि आपका प्रोग्राम किसी पते से पढ़ और लिख रहा होगा जो कुछ बाइट्स बंद हो सकता है। – justin

0

§5.3.4/10:

एक नई अभिव्यक्ति प्रकार std::size_t के पहले तर्क के रूप में आवंटन समारोह करने का अनुरोध किया स्थान की मात्रा से गुजरता है। यह तर्क ऑब्जेक्ट के आकार से कम नहीं होगा; यह से अधिक हो सकता है ऑब्जेक्ट का आकार केवल तभी बनाया जा सकता है जब ऑब्जेक्ट एक सरणी हो। चार और अहस्ताक्षरित चार की सरणियों के लिए, नई-अभिव्यक्ति और पता आवंटन समारोह द्वारा लौटाए का परिणाम के बीच अंतर किसी भी वस्तु का सबसे कड़े संरेखण आवश्यकता (3.9) का एक अभिन्न एकाधिक होगा टाइप करें जिसका आकार सरणी के आकार से अधिक नहीं है।

यह अन्य प्रकार के उचित रूप से आकार की वस्तुओं के स्थान-निर्माण के लिए नए के साथ आवंटित चार सरणियों का उपयोग कर सकते हैं। प्री-आवंटित बफर को ढेर पर आवंटित किया जाना है। अन्यथा आप alignment समस्याओं में भाग सकते हैं।

0

कुछ सिस्टमों पर, स्मृति पहुंच "गठबंधन" होना चाहिए। सादगी के लिए, इसका मतलब है कि पता किसी प्रकार के "alignemnt आवश्यकता" नामक कुछ पूर्णांक का एक होना चाहिए (सी ++ मानक के 3.9/5 देखें)।

तो, उदाहरण के लिए, मान लीजिए sizeof(int) == 4:

int *intarray = new int[2];  // 8 bytes 
char *charptr = (char *)intarray; // legal reinterpret_cast 
charptr += 1;      // still 7 bytes available 
*((int*)charptr) = 1;    // BAD! 

charptr का पता 4 की एक बहु नहीं है, इसलिए यदि int अपने मंच पर 4 की एक संरेखण की आवश्यकता है, तो कार्यक्रम व्यवहार अपरिभाषित है।

इसी

:

char ra[8]; 
int *intptr = reinterpret_cast<int*>(ra); 
intptr[0] = 1; // BAD! 

ra का पता 4.

एक बहु यह ठीक है, हालांकि होने की गारंटी नहीं है:

char ra = new char[8]; 
int *intptr = reinterpret_cast<int*>(ra); 
intptr[0] = 1; // NOT BAD! 

क्योंकि new गारंटी देता है कि चार सरणी आवंटन किसी भी प्रकार के लिए गठबंधन किया जाता है जो आवंटन में फिट करने के लिए पर्याप्त छोटा होता है (5.3.4/10)।

automatics से दूर चलना, यह देखना आसान है कि संकलक डेटा सदस्यों को संरेखित क्यों नहीं कर सकता है। पर विचार करें:

struct foo { 
    char first[1]; 
    char second[8]; 
    char third[3]; 
}; 

मानक की गारंटी है कि second 4-गठबंधन (अब भी यह सोचते हैं int 4-गठबंधन है कि) था, तो यह struct का आकार कम से कम कम से कम 16 (और उसके संरेखण आवश्यकता होना चाहिए था 4)। चूंकि मानक वास्तव में लिखा जाता है, इसलिए एक कंपाइलर को इस स्ट्रक्चर आकार 12 को देने की अनुमति नहीं है, बिना पैडिंग और कोई संरेखण आवश्यकता है।

+0

मुझे कुल मिलाकर पहला मिलता है, लेकिन मुझे नहीं पता कि दूसरा क्यों बुरा है। –

+0

ठीक है, पहले उदाहरण में 'charptr' की गारंटी 4 की एक बहु होने की गारंटी नहीं है, मैंने सुनिश्चित किया है कि 1 को गठबंधन मूल्य में जोड़कर। दूसरे उदाहरण में, 'आरए' एक पते पर हो सकता है जो 4 का एक बहु है, लेकिन फिर यह शायद नहीं हो सकता है। मानक किसी भी तरह से परवाह नहीं करता है। –

+0

हाँ, मुझे यह नहीं पता था कि पहला [1] एक गैर-गठबंधन पते पर शुरू हो सकता है। मुझे नहीं लगता था कि यह संभव था। –

0

char x[size*sizeof(T)];alignment खाते में नहीं ले सकता है, जहां टी एक्स [आकार]; मर्जी। alignment(2) एसएसई प्रकारों के साथ काम करते समय भी बहुत महत्वपूर्ण हो सकता है, जिसके लिए 16 बाइट संरेखण की आवश्यकता होती है

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