एक वेक्टर को दूसरे में कॉपी करने का तेज़ तरीका


155

मैं दो तरीके पसंद करता हूं:

void copyVecFast(const vec<int>& original)
{
  vector<int> newVec;
  newVec.reserve(original.size());
  copy(original.begin(),original.end(),back_inserter(newVec));
}

void copyVecFast(vec<int>& original)
{

  vector<int> newVec;
  newVec.swap(original); 
}

आप इसे कैसे करते हो?


14
दूसरे एक का नाम भ्रामक है - क्योंकि यह प्रतिलिपि नहीं है (हालांकि यह तेज़ है)।
अनाम

जवाबों:


126

यदि आप संदर्भ द्वारा तर्क भेजते हैं तो आपका दूसरा उदाहरण काम नहीं करता है। क्या आपका मतलब है

void copyVecFast(vec<int> original) // no reference
{

  vector<int> new_;
  new_.swap(original); 
}

यह काम करेगा, लेकिन एक आसान तरीका है

vector<int> new_(original);

अच्छा है, यह काम करता है। लेकिन यह वैक्टर की एक सरणी के लिए काम नहीं कर रहा है: उदाहरण के लिए: वेक्टर <int> A [n];
ABDDexter 7

8
वह अदला-बदली है, नकल नहीं।
sdd

1
@ एसडीएस - नहीं, यह नहीं है। तर्क सूची की जाँच करें। originalफ़ंक्शन तर्क की एक प्रति है।
रैलबोंड

249

वे हालांकि समान नहीं हैं, क्या वे हैं? एक कॉपी है, दूसरा स्वैप है । इसलिए फ़ंक्शन नाम।

मेरा मनपसंद है:

a = b;

कहां aऔर bवैक्टर हैं।


3
वास्तव में दृष्टिकोण मूल्य से गुजर रहा है, कंपाइलर कॉपी कंस्ट्रक्टर को कॉल करता है, और फिर उस नए बनाए गए तत्व को स्वैप करता है। यही कारण है कि आरएलबोंड एक ही प्रभाव को प्राप्त करने के लिए सीधे कॉपी कंस्ट्रक्टर को कॉल करने का सुझाव देता है।
डेविड रॉड्रिग्ज - dribeas

1
हालाँकि, आप बिना किसी फ़ंक्शन के rlbon को कॉल नहीं कर सकते हैं जो मूल रूप से वैल के रूप में गुजरता है। अन्यथा, मूल एक खाली हो जाएगा। दूसरा समाधान यह सुनिश्चित करता है कि आप हमेशा मूल्य से कॉल करेंगे और इसलिए आप मूल वेक्टर में तारीख नहीं खोएंगे। (संकेत
बिंदुओं के

बी के तत्वों को ए (ए = आकार के साथ बी छोड़ते हुए) को स्थानांतरित नहीं करेंगे?
जोनाथन।

1
@Jonathan। मान लें कि आप के बारे में बात कर रहे हैं a = bतो नहीं। असाइनमेंट का अर्थ है: बिना बदले aसमान बनाना । इसके विपरीत, उनकी सामग्री का आदान-प्रदान होता है (ताकि के अब होगा जो कुछ भी है से पहले किया गया था)। आप शायद एक चाल ऑपरेशन के बारे में सोच रहे हैं (जैसा कि सी ++ 11 में होता है, लेकिन इस तरह से एक साधारण असाइनमेंट में नहीं)। इस तरह की एक चाल , अहम, "दिलचस्प" स्थिति में निकल जाएगी - देखें stackoverflow.com/questions/17730689/…bbstd::swap(a, b)bsizeab
डैनियल ईयरविकर

1
@Jonathan। डबल एम्परसेंड पर ध्यान दें &&। उस संस्करण का उपयोग केवल एक संदर्भ संदर्भ के लिए किया जाएगा। यह किसी भी गैर-कास्ट वैल्यू (जैसे bऊपर मेरे उदाहरण में) से मेल नहीं खाएगा । आप बदल सकते हैं bकह कर एक में a = std::move(b);देखें en.cppreference.com/w/cpp/language/value_category जटिलता के भी अधिक के स्तर के लिए।
डैनियल इयरविकर

74

यह एक वेक्टर की प्रतिलिपि बनाने का एक और वैध तरीका है, बस इसके निर्माता का उपयोग करें:

std::vector<int> newvector(oldvector);

यह नए वेक्टर में उन्हें std::copyपूरा करने के लिए शुरू से खत्म करने के लिए पूरे वेक्टर चलने का उपयोग करने से भी सरल है std::back_insert

यह कहा जा रहा है, आपकी .swap()एक प्रति नहीं है, इसके बजाय यह दो वैक्टर स्वैप करता है। आप अब कुछ भी शामिल नहीं करने के लिए मूल को संशोधित करेंगे! जो नकल न हो।


19

सीधा जवाब:

  • एक =ऑपरेटर का उपयोग करें

हम एक वेक्टर से दूसरे में मान निर्दिष्ट करने std::vector::operator=के लिए कंटेनर के सार्वजनिक सदस्य फ़ंक्शन का उपयोग कर सकते हैं std::vector

  • एक कंस्ट्रक्टर फ़ंक्शन का उपयोग करें

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

सावधान:

  • प्रयोग नहीं करें std::vector::swap

std::vector::swapएक वेक्टर को दूसरे की नकल नहीं कर रहा है, यह वास्तव में दो वैक्टर के तत्वों की अदला-बदली कर रहा है, जैसा कि इसके नाम से पता चलता है। दूसरे शब्दों में, कॉपी करने के लिए स्रोत वेक्टर को संशोधित करने के बाद std::vector::swapकहा जाता है, जो संभवतः वह नहीं है जो आपसे अपेक्षित है।

  • गहरी या उथली नकल?

यदि स्रोत वेक्टर में तत्व अन्य डेटा के संकेत हैं, तो एक गहरी प्रतिलिपि कभी-कभी चाहिए।

विकिपीडिया के अनुसार:

एक गहरी प्रतिलिपि, जिसका अर्थ है कि फ़ील्ड को संदर्भित किया जाता है: कॉपी की जा रही वस्तुओं के संदर्भ के बजाय, किसी भी संदर्भित ऑब्जेक्ट के लिए नई प्रतिलिपि ऑब्जेक्ट बनाए जाते हैं, और बी में रखे गए इन संदर्भों को संदर्भित करते हैं।

दरअसल, डी कॉपी करने के लिए वर्तमान में C ++ में बिल्ट-इन तरीका नहीं है। उपरोक्त सभी तरीके उथले हैं। यदि एक गहरी प्रतिलिपि आवश्यक है, तो आप एक वेक्टर को पीछे छोड़ सकते हैं और मैन्युअल रूप से संदर्भ की प्रतिलिपि बना सकते हैं। वैकल्पिक रूप से, ट्रैवर्सिंग के लिए एक पुनरावृत्ति पर विचार किया जा सकता है। इटरेटर पर चर्चा इस सवाल से परे है।

संदर्भ

std::vectorCplusplus.com का पेज


14

आपको वैक्टर की नकल करने के लिए स्वैप का उपयोग नहीं करना चाहिए, यह "मूल" वेक्टर को बदल देगा।

मूल को नए के बजाय एक पैरामीटर के रूप में पास करें।


14
new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
new_vector = old_vector; // Method 2

-14

यदि वेक्टर ALREADY मौजूद है और आप इसे कॉपी करना चाहते हैं, तो आप ऐसा कर सकते हैं:

newVec.resize(oldVec.size());
memcpy(&newVec.at(0), &oldVec.at(0), oldVec.size());

1
कृपया याद न रखें इसके अलावा यह काम नहीं करेगा क्योंकि मेकपी बाइट्स में आकार लेता है। इसके अलावा यदि दूसरा वेक्टर पहले से मौजूद है तो आप newVec = oldVecवही कर सकते हैं जो अन्य उत्तरों में से एक के समान है।
FDinoff

हाँ आप सही है। मैंने वह नहीं देखा। @Finoff, हालांकि नीचे एक काम करता है, आप मेमसीपी का उपयोग नहीं करने का सुझाव क्यों देते हैं? यह newVec = oldVec की तुलना में बहुत तेज़ प्रतीत होता है। memcpy (& newVec.at (0), और oldVec.at (0), oldVec.size () * sizeof (int));
sgowd

1
सामान्य मामले में, अपने कॉपी कंस्ट्रक्टर को कॉल किए बिना किसी ऑब्जेक्ट को कॉपी करने से सूक्ष्म कीड़े हो सकते हैं। इस मामले में मैंने सोचा होगा कि उनका भी यही प्रदर्शन रहा होगा। अगर ऐसा नहीं होता तो मैं कहूंगा कि वेक्टर प्रदर्शन के अनुकूल नहीं था, क्योंकि यह पहले से ही ऐसा होना चाहिए। क्या आपने वास्तव में एक बेंचमार्क लिखा था?
FDinoff

मैं आपकी आलोचना नहीं कर रहा था .. मेरी टीम लीड ने भी यही सुझाव दिया और मैं समझने की कोशिश कर रहा था।
sgowd

(मुझे नहीं लगता था कि आप मेरी आलोचना कर रहे थे।) क्या अब भी कुछ ऐसा है जो आप नहीं समझते हैं?
एफडिनॉफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.