आप किसी सरणी की सामग्री को std :: वेक्टर में C ++ में बिना लूपिंग के कैसे कॉपी कर सकते हैं?


122

मेरे पास उन मानों की एक सरणी है जो कार्यक्रम के एक अलग हिस्से से मेरे फ़ंक्शन को पारित किए जाते हैं जिन्हें मुझे बाद में प्रसंस्करण के लिए संग्रहीत करने की आवश्यकता होती है। चूंकि मुझे नहीं पता कि डेटा को संसाधित करने का समय आने से पहले कितनी बार मेरे फ़ंक्शन को कॉल किया जाएगा, मुझे एक डायनेमिक स्टोरेज संरचना की आवश्यकता है, इसलिए मैंने एक को चुना std::vector। मैं push_backव्यक्तिगत रूप से सभी मूल्यों के लिए मानक लूप नहीं करना चाहता हूं , यह अच्छा होगा अगर मैं इसे सभी समान चीजों का उपयोग करके कॉपी कर सकता हूं memcpy

जवाबों:


117

यदि आप सरणी और सरणी आकार प्राप्त करने के बाद वेक्टर का निर्माण कर सकते हैं, तो आप बस कह सकते हैं:

std::vector<ValueType> vec(a, a + n);

... मान aलेना आपकी सरणी है और nइसमें शामिल तत्वों की संख्या है। अन्यथा, std::copy()w / resize()चाल करेगा।

memcpy()जब तक आप यह सुनिश्चित नहीं कर सकते कि मूल्य सादे पुराने डेटा (POD) प्रकार के हैं, मैं इससे दूर रहूँगा।

इसके अलावा, यह ध्यान देने योग्य है कि इनमें से कोई भी वास्तव में लूप के लिए बचा नहीं है - यह सिर्फ एक सवाल है कि आपको इसे अपने कोड में देखना है या नहीं। मानों की प्रतिलिपि बनाने के लिए O (n) रनटाइम प्रदर्शन अपरिहार्य है।

अंत में, ध्यान दें कि अधिकांश एसटीएल एल्गोरिदम के लिए सी-स्टाइल सरणियां पूरी तरह से वैध कंटेनर हैं - कच्चा सूचक इसके बराबर है begin()और ( ptr + n) के बराबर है end()


4
पुशअप और कॉलिंग_बैक खराब होने का कारण यह है कि आप वेक्टर को कई बार आकार देने के लिए मजबूर कर सकते हैं यदि सरणी काफी लंबी है।
bradtgmurray

@bradtgmurray: मुझे लगता है कि मेरे द्वारा सुझाए गए "दो पुनरावृत्तियों" वेक्टर निर्माणकर्ता का कोई भी उचित कार्यान्वयन तत्वों की आवश्यक संख्या प्राप्त करने के लिए पहले दो पुनरावृत्तियों पर std :: दूरी () को कॉल करेगा, फिर बस एक बार आवंटित करें।
ड्रू हॉल

4
@bradtgmurray: यहां तक ​​कि वेक्टर्स (घातांक "निरंतर समय") की घातीय वृद्धि के कारण भी push_back () बहुत बुरा नहीं होगा। मुझे लगता है कि रनटाइम केवल सबसे खराब स्थिति में 2x के क्रम पर होगा।
ड्रू हॉल

2
और अगर वेक्टर पहले से ही है, तो एक vec.clear (); vec.insert (vec.begin (), ए, ए + एन); साथ ही काम करेगा। तब आपको एक पॉइंटर होने की आवश्यकता नहीं होगी, बस एक पुनरावृत्तिकर्ता, और वेक्टर असाइनमेंट फ़ेल्री जनरल (और C ++ / STL तरीका) होगा।
MP24

6
निर्माण करने में असमर्थ एक अन्य विकल्प असाइन किया जाएगा : vec.assign(a, a+n)जो कॉपी और आकार से अधिक कॉम्पैक्ट होगा।
mMontu

209

यहाँ कई उत्तर दिए गए हैं और उन सभी के बारे में काम पूरा हो जाएगा।

हालाँकि कुछ भ्रामक सलाह है!

यहाँ विकल्प हैं:

vector<int> dataVec;

int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

// Method 1: Copy the array to the vector using back_inserter.
{
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 2: Same as 1 but pre-extend the vector by the size of the array using reserve
{
    dataVec.reserve(dataVec.size() + dataArraySize);
    copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}

// Method 3: Memcpy
{
    dataVec.resize(dataVec.size() + dataArraySize);
    memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));
}

// Method 4: vector::insert
{
    dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);
}

// Method 5: vector + vector
{
    vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
    dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());
}

वेक्टर :: इंसर्ट का उपयोग करते हुए एक लंबी कहानी लघु विधि 4 में कटौती करना, bsruth के परिदृश्य के लिए सबसे अच्छा है।

यहाँ कुछ गोर विवरण हैं:

विधि 1 शायद समझना सबसे आसान है। बस सरणी से प्रत्येक तत्व को कॉपी करें और इसे वेक्टर की पीठ में धकेल दें। काश, यह धीमा है। क्योंकि एक लूप है (कॉपी फ़ंक्शन के साथ निहित), प्रत्येक तत्व को व्यक्तिगत रूप से व्यवहार किया जाना चाहिए; इस तथ्य के आधार पर कोई प्रदर्शन सुधार नहीं किया जा सकता है कि हम जानते हैं कि सरणी और वैक्टर सन्निहित ब्लॉक हैं।

विधि 2 विधि 1 के लिए एक सुझाया गया प्रदर्शन सुधार है; इसे जोड़ने से पहले केवल सरणी का आकार पूर्व-आरक्षित करें। बड़े सरणियों के लिए यह मदद कर सकता है। हालांकि यहां सबसे अच्छी सलाह यह है कि आप रिजर्व का उपयोग तब तक न करें जब तक कि प्रोफाइलिंग आपको सुझाव न दे कि आप एक सुधार प्राप्त कर सकते हैं (या आपको यह सुनिश्चित करने की आवश्यकता है कि आपके पुनरावृत्तियों को अमान्य नहीं किया जाएगा)। बज्ने सहमत हैं । संयोग से, मैंने पाया है कि इस विधि का प्रदर्शन किया धीमी समय के सबसे हालांकि मैं व्यापक व्याख्या करने के लिए कारण है कि यह नियमित रूप से था संघर्ष कर रहा हूँ काफी धीमी विधि 1 से ...

विधि 3 पुराने स्कूल समाधान है - समस्या पर कुछ सी फेंक दें! POD प्रकारों के लिए ठीक और तेज़ काम करता है। इस मामले में वेक्टर की सीमा के बाहर मेमसीपी कार्यों के बाद आकार बदलने की आवश्यकता है और वेक्टर को यह बताने का कोई तरीका नहीं है कि इसका आकार बदल गया है। इसके अलावा एक बदसूरत समाधान (बाइट कॉपी करना!) याद रखें कि यह केवल POD प्रकारों के लिए उपयोग किया जा सकता है । मैं इस समाधान का उपयोग कभी नहीं करूंगा।

विधि 4 जाने का सबसे अच्छा तरीका है। यह अर्थ स्पष्ट है, यह (आमतौर पर) सबसे तेज़ है और यह किसी भी वस्तु के लिए काम करता है। इस एप्लिकेशन के लिए इस पद्धति का उपयोग करने के लिए कोई नकारात्मक पहलू नहीं है।

विधि 5 विधि 4 पर एक ट्वीक है - सरणी को वेक्टर में कॉपी करें और फिर इसे जोड़ें। अच्छा विकल्प - आम तौर पर फास्ट-ईश और स्पष्ट।

अंत में, आप जानते हैं कि आप ऐरे के स्थान पर वैक्टर का उपयोग कर सकते हैं, है ना? जब कोई फ़ंक्शन सी-स्टाइल सरणियों की अपेक्षा करता है, तो आप वैक्टर का उपयोग कर सकते हैं:

vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");

आशा है कि वहाँ किसी को मदद करता है!


6
आप सुरक्षित रूप से और आंशिक रूप से "& dataArray [dataArraySize]" का संदर्भ नहीं दे सकते हैं - यह एक अतीत के अंत सूचक / पुनरावृत्ति को डीरेफर कर रहा है। इसके बजाय, आप कह सकते हैं dataArray + dataArraySize को पॉइंटर प्राप्त करने के लिए पहले इसे डीरेफेरेंस किए बिना।
ड्रू हॉल

2
@ ड्रू: हाँ, आप कर सकते हैं, कम से कम सी। में यह परिभाषित किया गया है कि &exprइसका मूल्यांकन नहीं होता है expr, यह केवल इसके पते की गणना करता है। और एक सूचक एक अंतिम तत्व के बाद पूरी तरह से वैध है, भी है।
रोलैंड इलिग

2
क्या आपने विधि 4 को 2 के साथ करने की कोशिश की है? डालने से पहले स्थान को जमा करना। ऐसा लगता है कि यदि डेटा का आकार बड़ा है, तो कई सम्मिलन के लिए कई वास्तविकताओं की आवश्यकता होगी। क्योंकि हम आकार को प्राथमिकता से जानते हैं, हम डालने से पहले, वास्तविककरण कर सकते हैं।
जॉर्ज लेइताओ

2
@ मैटीटी 5 विधि 5 क्या है? डेटा की मध्यवर्ती प्रतिलिपि क्यों बनाते हैं?
रुस्लान

2
मैं व्यक्तिगत रूप से एरियर्स से पॉइंटर्स को स्वचालित रूप से कम करने के बजाय लाभ प्राप्त करूंगा: dataVec.insert(dataVec.end(), dataArray, dataArray + dataArraySize);- मेरे लिए बहुत स्पष्ट है। विधि 5 से कुछ भी हासिल नहीं कर सकते हैं, केवल बहुत ही अक्षम दिखता है - जब तक कि कंपाइलर वेक्टर को फिर से अनुकूलित करने में सक्षम न हो।
एकनकागुआ

37

यदि आप सभी कर रहे हैं मौजूदा डेटा की जगह ले रहा है, तो आप ऐसा कर सकते हैं

std::vector<int> data; // evil global :)

void CopyData(int *newData, size_t count)
{
   data.assign(newData, newData + count);
}

1
समझने में सरल और निश्चित रूप से सबसे तेज समाधान (यह पर्दे के पीछे सिर्फ एक यादगार है)।
डॉन स्कॉट

क्या deta.assign data.insert से तेज है?
जिम


10

चूंकि मैं केवल अपने स्वयं के उत्तर को संपादित कर सकता हूं, इसलिए मैं अपने प्रश्न के अन्य उत्तरों से एक समग्र उत्तर बनाने जा रहा हूं। आप सभी को धन्यवाद जिन्होंने उत्तर दिया।

Std :: copy का उपयोग करके , यह अभी भी पृष्ठभूमि में पुनरावृत्त करता है, लेकिन आपको कोड टाइप करने की आवश्यकता नहीं है।

int foo(int* data, int size)
{
   static std::vector<int> my_data; //normally a class variable
   std::copy(data, data + size, std::back_inserter(my_data));
   return 0;
}

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

vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));

मैं इस दृष्टिकोण की सिफारिश करने जा रहा था।
17

यदि आप समय से पहले आकार जानते हैं, और बैक_इनसर का उपयोग नहीं करते हैं, तो यह आपके वेक्टर फ्रंट को आकार देने के लिए सबसे अधिक कुशल है।
ल्यूक

आप my_data.reserve (आकार) जोड़ सकते हैं
डेविड

ध्यान दें कि आंतरिक रूप से यह वही कर रहा है जिससे आप बचना चाहते हैं। यह बिट्स की नकल नहीं है, यह सिर्फ लूपिंग और कॉलिंग_बैक () है। मुझे लगता है कि आप केवल कोड लिखने से बचना चाहते थे?
mmocny

1
Wjy डेटा को कॉपी करने के लिए वेक्टर कंस्ट्रक्टर का उपयोग नहीं करते हैं?
मार्टिन यॉर्क

3

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


8
हो सकता है कि यह अन्य उत्तरों में से एक पर टिप्पणी हो, क्योंकि आप वास्तव में समाधान का प्रस्ताव नहीं करते हैं।
फिन जुव

3
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//source

unsigned dataArraySize = sizeof(dataArray) / sizeof(int);

std::vector<int> myvector (dataArraySize );//target

std::copy ( myints, myints+dataArraySize , myvector.begin() );

//myvector now has 1,2,3,...10 :-)

2
जबकि इस कोड स्निपेट का स्वागत है, और कुछ मदद प्रदान कर सकता है, यह हो जाएगा काफी सुधार हुआ है, तो यह उसका स्पष्टीकरण शामिल की कैसे और क्यों इस को हल करती है समस्या। याद रखें कि आप भविष्य में पाठकों के लिए सवाल का जवाब दे रहे हैं, न कि केवल उस व्यक्ति से जो अब पूछ रहा है! कृपया स्पष्टीकरण जोड़ने के लिए अपने उत्तर को संपादित करें, और इस बात का संकेत दें कि क्या सीमाएँ और मान्यताएँ लागू होती हैं।
टोबे स्पाइट

4
रुको, क्या है myints?
मावविल्ज

2

फिर भी एक अन्य उत्तर, चूंकि उस व्यक्ति ने कहा "मुझे नहीं पता कि मेरे कार्य को कितनी बार कहा जाएगा", आप वेक्टर सम्मिलित विधि का उपयोग कर सकते हैं, ताकि वेक्टर के अंत तक मानों की सरणियों को जोड़ सकें:

vector<int> x;

void AddValues(int* values, size_t size)
{
   x.insert(x.end(), values, values+size);
}

मुझे इस तरह से पसंद है क्योंकि वेक्टर के कार्यान्वयन को इट्रेटर प्रकार और प्रकार के आधार पर मूल्यों को सम्मिलित करने के सर्वोत्तम तरीके के लिए अनुकूलन करने में सक्षम होना चाहिए। आप stl के कार्यान्वयन पर कुछ हद तक जवाब दे रहे हैं।

यदि आपको सबसे तेज गति की गारंटी देने की आवश्यकता है और आप जानते हैं कि आपका प्रकार एक POD प्रकार है तो मैं थॉमस के उत्तर में आकार बदलने की विधि की सिफारिश करूंगा:

vector<int> x;

void AddValues(int* values, size_t size)
{
   size_t old_size(x.size());
   x.resize(old_size + size, 0);
   memcpy(&x[old_size], values, size * sizeof(int));
}

1

उपरोक्त विधियों के अलावा, आपको यह सुनिश्चित करने की आवश्यकता है कि आप या तो std :: वेक्टर.reserve (), std :: वेक्टर.resize () का उपयोग करें या वेक्टर के आकार का निर्माण करें, यह सुनिश्चित करने के लिए कि आपके वेक्टर में पर्याप्त तत्व हैं। अपना डेटा रखने के लिए। यदि नहीं, तो आप स्मृति को दूषित कर देंगे। यह std :: copy () या memcpy () दोनों में से एक है।

यह वेक्टर.push_back () का उपयोग करने का कारण है, आप वेक्टर के अंत में नहीं लिख सकते हैं।


यदि आप एक back_inserter का उपयोग कर रहे हैं, तो आपको उस वेक्टर के आकार को प्री-रिजर्व करने की आवश्यकता नहीं है जिसका आप कॉपी कर रहे हैं। back_inserter एक push_back () करता है।
जॉन डिब्लिंग

0

मान लें कि वेक्टर में आइटम कितना बड़ा है:

std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));

http://www.cppreference.com/wiki/stl/vector/start


क्या यह एसटीडी के कार्यान्वयन पर निर्भर नहीं है :: वेक्टर?
ReaperUnreal

यह खराब है! आप सरणी को दो बार भर रहे हैं, '0' के साथ, फिर उचित मानों के साथ। बस करो: std :: वेक्टर <int> myArray (स्रोत, स्रोत + आइटम_काउंट); और memcpy का उत्पादन करने के लिए अपने संकलक पर भरोसा!
क्रिस जेफरसन

अपने संकलक को __mccpy_int_aligned बनाने का भरोसा दें; यह और भी तेज होना चाहिए
MSalters
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.