2012-03-20 22 views
8

का उपयोग कर डबल (द्वि-आयामी) सरणी मेरे पास पॉइंटर से पॉइंटर द्वारा आवंटित एक डबल सरणी है।std :: unique_ptr

// pointer to pointer 
    int **x = new int *[5]; // allocation 
    for (i=0; i<5; i++){ 
     x[i] = new int[2]; 
    } 

    for (i=0; i<5; i++){  // assignment 
     for (j=0; j<2; j++){ 
      x[i][j] = i+j; 
     } 
    } 

    for (i=0; i<5; i++) // deallocation 
     delete x[i]; 
    delete x; 

मैं unique_ptr का उपयोग कर यह करने के लिए कोशिश कर रहा हूँ:

std::unique_ptr<std::unique_ptr<int>[]> a(new std::unique_ptr<int>[5]); 
    for (i=0; i<5; i++) 
     a[i] = new int[2]; 

लेकिन वह no operator = matches these operands कह एक त्रुटि हो रही है। मैं यहाँ क्या गलत कर रहा हूँ?

उत्तर

2

आपका कोड प्रभावी रूप से int के सरणी की सरणी में हेरफेर कर रहा है।

std::vector<std::vector<int> > x; 

यह unique_ptr के लिए एक अच्छा मामला नहीं है:

C++ में आप सामान्य रूप से के रूप में यह लागू करना चाहते हैं। साथ ही, आपको point_sr को पॉइंटर्स का उपयोग करने और गतिशील रूप से unique_ptr ऑब्जेक्ट आवंटित करने की आवश्यकता नहीं है। Unique_ptr का पूरा बिंदु पॉइंटर्स के उपयोग को खत्म करना और वस्तुओं के स्वचालित आवंटन और विध्वंस प्रदान करना है।

+0

आपके इनपुट के लिए धन्यवाद। जिस तरह से मैं unique_ptr को समझता हूं वह यह सुनिश्चित करता है कि यह उदाहरण केवल 1 संदर्भ में इंगित करता है। तो एक मैट्रिक्स बनाने के लिए unique_ptr को इंगित करने के लिए unique_ptr का उपयोग करना अद्वितीय_ptr का उपयोग करने के लिए ठीक होना चाहिए, यह देखते हुए कि उदाहरण के लिए कोई और संदर्भ नहीं होगा। इसके अलावा, मुझे अंतिम वाक्य के पीछे कारण समझ में नहीं आता है। धन्यवाद। – Evan

+0

किसी भी आरएआईआई कक्षा को वही अनूठी गारंटी प्रदान करनी चाहिए। अधिकांश सी ++ कक्षाएं आरएआईआई हैं। तो आपको नौकरी के लिए सही उपकरण का उपयोग करना चाहिए। वेक्टर और सरणी को unique_ptr को यहां प्राथमिकता दी जानी चाहिए। –

+0

अद्वितीय ptrs का कारण अधिकतर गतिशील आवंटित एकल ऑब्जेक्ट्स को पकड़ने के लिए होता है। मैं एक array_ptr में एक सरणी को स्टोर करने के कारण के बारे में तुरंत सोच नहीं सकता। –

15

आप को std::unique_ptr<int[]> पर असाइन नहीं कर सकते हैं, जो आपकी त्रुटि का कारण है। सही कोड

 a[i] = std::unique_ptr<int[]>(new int[2]); 

है हालांकि, piokuc सही है, तो यह है कि यह, अत्यधिक सरणियों के लिए unique_ptr उपयोग करने के लिए असामान्य है के रूप में है कि क्या std::vector और std::array के लिए कर रहे हैं, पर यदि आकार समय से आगे जाना जाता है निर्भर करता है।

//make a 5x2 dynamic jagged array, 100% resizable any time 
std::vector<std::vector<int>> container1(5, std::vector<int>(2)); 
//make a 5x2 dynamic rectangular array, can resize the 5 but not the 2 
std::vector<std::array<2, int>> container1(5); 
//make a 5x2 automatic array, can't resize the 2 or 5 but is _really fast_. 
std::array<5, std::array<2, int>> container; 

इन सभी के प्रारंभ जा सकता है और कोड आप पहले से ही था के रूप में सिर्फ एक ही इस्तेमाल किया, सिवाय इसके कि वे का निर्माण करने के लिए आसान कर रहे हैं, और आप उन्हें नष्ट करने के लिए नहीं है।

+1

बेशक, 'std :: unique_ptr (नया int [2]); 'गलत डिलीटर होगा - जो' std :: unique_ptr (नया int [2]) होना चाहिए; '। प्रीपेप्टिव +1 मानते हुए कि आप इसे ठीक करेंगे। ; -] – ildjarn

+0

@ildjarn: मैंने कभी भी arrays के 'unique_ptr' का उपयोग नहीं किया है, मैं वाक्यविन्यास पर अस्पष्ट हूं। धन्यवाद! –

+0

आपके इनपुट के लिए धन्यवाद! – Evan

2
for (i=0; i<5; i++) // deallocation 
     delete x[i]; 
    delete x; 

नहीं नहीं नहीं नहीं

delete [] x[i]; 
delete [] x; 

// यो

1

केवल कारणों मैं std :: unique_ptr उपयोग करने के लिए (या बढ़ावा :: scoped_array कहते हैं) एसटीडी से अधिक के बारे में सोच सकते हैं :: सरणी रखने के लिए वेक्टर आमतौर पर लागू नहीं होते हैं ...

1) यह 1 या 2 पॉइंटर्स मेमोरी के लायक बचाता है, अगर आप जानते हैं कि सभी सरणी का आकार क्या है [अप्रासंगिक जब तक आपके पास बड़ी संख्या में नहीं है SMA ll arrays]

2) यदि आप केवल कुछ फ़ंक्शन में सरणी को पार कर रहे हैं जो सी शैली सरणी या कच्चे सूचक की अपेक्षा करता है, तो यह अधिक प्राकृतिक फिट जैसा महसूस हो सकता है। std :: वेक्टर अनुक्रमिक भंडारण पर होने की गारंटी है, इसलिए इस तरह के फ़ंक्शन में (a.empty() ? nullptr : &a[0], a.size()) गुजरना 100% कानूनी भी है।

3) एमएसवीसी डीबग मोड में मानक कंटेनर डिफ़ॉल्ट रूप से "चेक" होते हैं और बहुत धीमे होते हैं, जो बड़े डेटासेट पर वैज्ञानिक प्रोग्रामिंग करते समय परेशान हो सकते हैं।

+0

वेक्टर पर unique_ptr का एक लाभ यह है कि आप प्रारंभिकरण से बच सकते हैं, जिसकी कीमत कुछ मामलों में महत्वपूर्ण हो सकती है। रेफरी http://stackoverflow.com/questions/96579/stl-vectors-with-uninitialized- स्टोरेज और http://stackoverflow.com/questions/7546620/operator- new-initializes-memory-to-zero – goertzenator

4

आप एक std::array या एक गतिशील आवंटित सरणी के बजाय एक std::vector का उपयोग कर के लक्जरी नहीं है, तो आप एक unique_ptr सी ++ 11 में एक दो आयामी सरणी के लिए इस प्रकार के रूप में उपयोग कर सकते हैं:

std::unique_ptr<int*, std::function<void(int**)>> x(
    new int*[10](), 
    [](int** x) { 
     std::for_each(x, x + 10, std::default_delete<int[]>()); 
     delete[] x; 
    } 
); 

unique_ptr घोषणा पंक्ति सरणी के आयाम आवंटित करने का ख्याल रखती है। new int*[10]() में पिछला () यह सुनिश्चित करता है कि प्रत्येक कॉलम सूचक nullptr पर प्रारंभ किया गया हो। पाश के लिए

एक तो आवंटित स्तंभ सरणियों:

for (size_t row = 0; row < 10; ++row) { 
    (x.get())[row] = new int[5]; 
} 

unique_ptr क्षेत्र से बाहर हो जाता है, अपने कस्टम Deleter लैम्ब्डा समारोह पंक्ति सरणी को हटाने से पहले स्तंभ सरणियों को हटाने का ख्याल रखता है। for_each अभिव्यक्ति default_delete फ़ैक्टर का उपयोग करती है।

+0

क्या यह हो सकता है '_mm_malloc' और कैसे उपयोग कर विस्तारित? –

+0

स्मृति आवंटित करने के लिए '__mm_malloc' का उपयोग करें और कस्टम डिलीटर में' _mm_free' का उपयोग करें। – sakra

+0

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

0

एक उदाहरण आगे मुझे इस समाधान

size_t k = 10; 
std::unique_ptr<int*, std::function<void(int**)>> y(new int*[k](), 
    [](int** x) {delete [] &(x[0][0]); 
       delete[] x;}); 

// Allocate the large array 
y.get()[0] = new int[k*10]; 

// Establish row-pointers 
for (size_t row = 0; row < k; ++row) { 
    (y.get())[row] = &(y.get()[0][0]); 
} 

यहाँ सभी आयामों गतिशील हो सकता है और आप एक वर्ग के अंदर लपेट और एक ऑपरेटर [] का पर्दाफाश कर सकते हैं के लिए प्रेरित किया। इसके अलावा स्मृति को एक संगत तरीके से आवंटित किया जाता है और आप आसानी से आवंटित स्मृति आवंटित कर सकते हैं, जो गठबंधन स्मृति आवंटित करता है।

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