2014-07-17 13 views
6

मेरे ज्ञान बहुत अल्पविकसित है, लेकिन जब यह जो मैं जानता हूँ कुछ इस तरह ढेर पर बनाई गई है से arrays के लिए आता है,टेम्पलेट पैरामीटर के रूप में ऐरे: ढेर या ढेर? ढेर की तुलना में ढेर के

float x[100]; 

जबकि कुछ इस तरह पर बनाई गई है ढेर

float* x = new float[100]; 

लेकिन क्या होता है अगर मैं एक टेम्पलेट सरणी वर्ग बनाने के लिए, और एक "ढेर" सरणी प्रकार (float[100] की तरह) में इसे पारित? उदाहरण:

#include <iostream> 

using namespace std; 

template <class T> 
class Array { 
public: 
    int size; 
    T* data; 

    Array(int size_) : size(size_) { 
     data = new T[size]; 
    } 

    ~Array() { 
     delete [] data; 
    } 
}; 

int main() { 
    int m = 1000000; 
    const int n = 100; 
    Array<float[n]>* array = new Array<float[n]>(m); 

    for (int i = 0; i < m; i++) 
     for (int j = 0; j < n; j++) 
      array->data[i][j] = i * j; 

    cout << array->data[10][9] << endl; 
    delete array; 
} 

यहां वास्तव में क्या चल रहा है? क्या यह स्मृति ढेर, या ढेर पर बनाई गई है? मेरा अनुमान ढेर है, लेकिन यह कैसे काम करता है? क्या संकलक स्मृति के एक बड़े ब्लॉक को आवंटित करता है, और उसके बाद पॉइंटर्स स्टोर करता है जो प्रत्येक n तत्वों में सूचकांक करता है? या क्या यह स्मृति के कई छोटे ब्लॉक (आवश्यक रूप से संगत नहीं) आवंटित करता है, और प्रत्येक ब्लॉक में स्टोर पॉइंटर्स आवंटित करता है?

इसके अलावा, मैं टेम्पलेट की सहायता के बिना ऐसा नहीं कर सकता। विशेष रूप से, यह कोड संकलित नहीं करता है:

int m = 1000; 
const int n = 100; 
(float[n])* array = new (float[n])[m]; 

यहां क्या हो रहा है?

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

वाक्य रचना सुझावों के लिए धन्यवाद, हर कोई। क्या मैं सच में में दिलचस्पी थी क्या ब्लॉक

int m = 1000; 
const int n = 100; 
float (*array)[n] = new float[m][n]; 

में क्या होता है, लेकिन मैं कैसे टेम्पलेट्स के उपयोग के बिना यह लिखने के लिए पता नहीं था है। एक चीज जिसमें मुझे वास्तव में दिलचस्पी थी, यदि संकलक ढेर पर एक बड़े ब्लॉक के रूप में आवंटित करता है, तो आप प्रत्येक एन-वें तत्व को पॉइंटर्स संग्रहीत किए बिना किसी विशेष तत्व तक पहुंचने के लिए सिंटैक्स array[i][j] का उपयोग कैसे कर सकते हैं? तब मुझे एहसास हुआ कि n स्थिर है, sizeof(float[n]) तय है, इसलिए जब आप सरणी बनाते हैं, तो संकलक m तत्वों की एक सरणी आवंटित कर रहा है जहां प्रत्येक तत्व float[n] है, जो मेरे मामले में 100 * 4 = 400 बाइट्स है। नाउ इट आल मेक्स सेंस। धन्यवाद!

+2

आप तीन के नियम का उल्लंघन किया। मैं जानता हूँ कि यह बात करने के लिए संबंधित नहीं है, लेकिन यह देखकर या स्वचालित रूप से एक नाशक परिभाषा टाइपिंग की घंटी चेतावनी अंगूठी है और आप कॉपी करने और काम के बारे में सोचने के लिए प्राप्त करने के लिए एक अच्छी आदत है। (और यदि आप परेशान नहीं करना चाहते हैं, तो उन्हें C++ 03 में निजी घोषित करें या सी ++ 11 में हटा दिया गया है)। – aschepler

उत्तर

2

आपने अपने सरणी को पीछे की तरफ लिखा है। यह काम करता है:

using A = float[n]; 
    A* array = new A[m]; 

या

// at file scope 
template<typename T, unsigned N> using add_extent = T[N]; 
// ... 
    add_extent<float, n>* array = new add_extent<float, n>[m]; 

एक बहुआयामी सरणी:

int m = 1000; 
    const int n = 100; 
    float (*array)[n] = new float[m][n]; 
    delete[] array; 

आप एक ही आदेश में आप एक प्रकार उपनाम या उचित टेम्पलेट का उपयोग कर सकते हैं में सरणी विस्तार रखना चाहते हैं चाहे ढेर या ढेर पर m*n तत्वों के एक ब्लॉक के रूप में आवंटित किया गया हो।जब आप सरणी प्रकार (जैसे float (*array)[n]) के सूचक को इंडेक्स करते हैं, तो संकेतक सरणी प्रकार के चरण के अनुसार n तत्वों को एक समय में बढ़ाया जाता है।

+0

मैंने देखा है बहुआयामी सरणियों अलग ब्लॉक के रूप में किया: 'नाव ** data2 = नई नाव * [मीटर]; के लिए (int i = 0; i hunse

+0

@ हंस जो संभव है, लेकिन एक ब्लॉक की तुलना में अक्षम है। ध्यान दें कि 'फ्लोट **' 'float (*) [N]' के लिए एक अलग प्रकार है। – ecatmur

+0

@ हंस यदि आप एकाधिक चर आयाम वाले सरणी के बारे में सोच रहे हैं, तो लाइब्रेरी समाधान हैं जो अभी भी आपको एक आवंटन देते हैं, और आपके लिए इंडेक्स अंकगणित करते हैं, मुख्य रूप से बूस्ट। मल्टीएरे: http://www.boost.org/doc /libs/1_55_0/libs/multi_array/doc/user.html – ecatmur

1

सभी मेमोरी ढेर पर जाती है। कंपाइलर सरणी के सरणी के लिए स्मृति का एक विशाल हिस्सा आवंटित करता है, और अनुक्रमण को सेट करता है ताकि यह पहुंच योग्य हो।

और एक तरफ के रूप में यदि कोई भी आपकी Array कक्षा की प्रतिलिपि या असाइन करता है तो आप स्मृति को रिसाव करेंगे और/या डबल हटा देंगे।

3
Array<float[n]>* array = new Array<float[n]>(m); 

यहाँ क्या हो रहा है दो ढेर आवंटन है। Array ऑब्जेक्ट को ढेर पर आवंटित किया जाएगा क्योंकि आपने इसे बनाने के लिए new का उपयोग किया था। नई अभिव्यक्तिArray कन्स्ट्रक्टर को कॉल करती है, जो फिर new का उपयोग सरणी data आवंटित करने के लिए करती है; इसलिए data भी ढेर पर आवंटित किया जाता है।

यह यह करने के लिए बेहतर है:

Array<float[n]> array(m); 

यह स्टैक पर array आवंटित (इसलिए यह स्वचालित रूप से ब्लॉक के अंत में नष्ट हो जाएगा)। हालांकि, array ऑब्जेक्ट स्वयं स्टैक पर है, डेटा अभी भी ढेर पर संग्रहीत है क्योंकि इसे Array कन्स्ट्रक्टर में ढेर पर आवंटित किया गया है। यह तब होता है जब आपके पास std::vector या std::string स्थानीय चर होता है।

इसके अलावा, मैं टेम्पलेट की सहायता के बिना ऐसा नहीं कर सकता। विशेष रूप से, इस कोड संकलन नहीं करता है:

यह सिर्फ इसलिए कि अपने वाक्य रचना गलत है। सही सिंटैक्स है:

float (*array)[n] = new float[m][n]; 

बाएं हाथ की ओर एक सरणी के लिए एक सूचक की घोषणा करने के लिए सही रास्ता दिखाता है। दाईं ओर, आप mfloat[n] एस की एक सरणी चाहते हैं। यह float[m][n] दर्शाया गया है; [m] अंत में नहीं जाता है।

0

लाइन में

Array<float[n]>* array = new Array<float[n]>(m); 

Array<T> का एक उदाहरण ढेर पर आवंटित किया जाता है। आप पहले ही समझ चुके हैं कि, सामान्य रूप से आवंटन के बारे में आपका पहला बयान दिया गया है।

शायद भ्रमित करने वाला हिस्सा टेम्पलेट पैरामीटर के रूप में float[n] का उपयोग है?

टेम्पलेट पैरामीटर T, जैसा कि class द्वारा आपकी Array की परिभाषा में दर्शाया गया है, एक प्रकार का प्रतिनिधित्व करता है। यह खुद आवंटन के किसी भी रूप से संबंधित नहीं है।

इस का एक प्रदर्शन के रूप में, के जो अपने पैरामीटर के किसी भी उपयोग नहीं है एक साधारण टेम्पलेट लिखने करते हैं:

#include <cassert> 

using namespace std; 

template <typename T> 
class A { 
}; 

int main(){ 

    A<float[100]> a1; 
    A<float[1000]> a2; 
    float f[100]; 

    assert(sizeof(a1) == sizeof(a2)); 
    cout << "a1 : " << sizeof(a1) << endl; 
    cout.<< "f : " << sizeof(f) << endl; 
} 

आउटपुट:

a1 : 1 
f : 400 

तो यहाँ float[n] वास्तव में एक प्रकार है (1)

दूसरी तरफ, जब आप कीवर्ड new का उपयोग करते हैं, तो आप जानते हैं कि ढेर पर कुछ आवंटित किया जा रहा है। तो जैसा कि मैंने कहा, array वैरिएबल ढेर में एक स्मृति खंड को इंगित करेगा।इसके अलावा टेम्पलेट में ही एक ढेर आवंटन होता है (फिर से, कीवर्ड new)।

अंत में, मैं मूल आधार है कि new एक ढेर आवंटन को इंगित करता है अति सूक्ष्म अंतर करना चाहते हैं। जबकि डिफ़ॉल्ट रूप से यह मामला है, जब placement मोड में इस्तेमाल किया, वास्तविक आवंटन बहुत अच्छी तरह से ढेर पर हो सकता है।


(1) ध्यान दें कि सी ++ यह रूप में इस तरह क्योंकि n एक निरंतर के रूप में घोषित किया जाता है, और इस प्रकार है, जिसके परिणामस्वरूप प्रकार संकलन समय में मूल्यांकन किया जा सकता स्वीकार करता है। n की परिभाषा की const विशेषता निकालें, और संकलक शिकायत करेंगे।

+0

इसके अलावा, आपके अन्य प्रश्न को अन्य उत्तरों में अच्छी तरह से संबोधित किया गया है। – didierc

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