C ++ वेक्टर का इंसर्ट और पुश_बैक अंतर


79

मुझे पता है कि बीच का अंतर (रों) कर रहे हैं क्या चाहते हैं vectorकी push_backऔर insertकार्य करता है।

क्या कोई संरचनात्मक अंतर है?

क्या वास्तव में बड़ा प्रदर्शन अंतर है?


4
insertइसे कहीं भी कर सकते हैं, और इसमें रेंज सपोर्ट जैसी अन्य चीजें शामिल हैं। push_backअंत में जोड़ने के लिए अधिक सुविधाजनक है।
क्रिस

जवाबों:


93

सबसे बड़ा अंतर उनकी कार्यक्षमता है। push_backहमेशा के अंत में एक नया तत्व रखता है vectorऔर insertआपको नए तत्व की स्थिति का चयन करने की अनुमति देता है। यह प्रदर्शन को प्रभावित करता है। vectorतत्वों को केवल मेमोरी में स्थानांतरित किया जाता है जब इसकी लंबाई बढ़ाना आवश्यक होता है क्योंकि इसके लिए बहुत कम मेमोरी आवंटित की गई थी। दूसरी ओर insertएक नए तत्व की चयनित स्थिति के बाद सभी तत्वों को स्थानांतरित करने के लिए मजबूर करता है। आपको बस इसके लिए जगह बनानी होगी। यही कारण है कि insertअक्सर की तुलना में कम कुशल हो सकता है push_back


9
दूसरी ओर, अंत में डालने के रूप में के रूप में कुशल होना चाहिए push_back
मैथ्यू एम।

18
खैर, लगभग कुशल के रूप में - कोड निर्धारित करने के लिए कि जरूरत है insertपर वास्तव में है end(), इसलिए वहाँ अधिक शाखाओं में होने जा रहे हैं insertकी तुलना में push_back, जब तक कि संकलक यह पता लगाने कि वे वास्तव में आवश्यक नहीं हैं कर सकते हैं।
यक्क - एडम नेवरुमोंट १०'१२ १akk

5
@TomerW लोग C या C ++ को चुनने के लिए हर एक मशीन चक्र को सक्षम करने में सक्षम हो सकते हैं, प्रदर्शन को बढ़ाने के लिए, कभी-कभी ASM में सीधे लिखने के बिंदु पर ... हर "यदि" मायने रखता है, तो यह जावा नहीं है ..
सीजर

1
@ सीजर इसका कारण यह नहीं है कि आप अपने लंग को चुनते हैं ... सीपीपी तेज हो सकता है फिर सी, और इसके विपरीत ... नरक, कुछ मामलों में यहां तक ​​कि जावा भी तेज हो सकता है, फिर इसके रनटाइम अनुकूलन के लिए सी।
तोमर डब्ल्यू

@ टॉमरडब्ल्यू हो, तो क्यों? कृपया मुझे बताएं।
सीजर

32

कार्यों के अलग-अलग उद्देश्य हैं। vector::insertआपको किसी ऑब्जेक्ट को एक निर्दिष्ट स्थान पर सम्मिलित करने की अनुमति देता है vector, जबकि vector::push_backअंत में ऑब्जेक्ट को चिपका देगा। निम्नलिखित उदाहरण देखें:

using namespace std;
vector<int> v = {1, 3, 4};
v.insert(next(begin(v)), 2);
v.push_back(5);
// v now contains {1, 2, 3, 4, 5}

आप उपयोग कर सकते हैं insertके रूप में एक ही काम को करने के लिए push_backके साथ v.insert(v.end(), value)


9

तथ्य यह है कि बगल push_back(x)के रूप में ही करता है insert(x, end())(शायद थोड़ा बेहतर प्रदर्शन के साथ), इन कार्यों के बारे में पता करने के लिए कई महत्वपूर्ण बात कर रहे हैं:

  1. push_backकेवल BackInsertionSequenceकंटेनरों पर मौजूद है - इसलिए, उदाहरण के लिए, यह मौजूद नहीं है set। यह इसलिए नहीं हो सका क्योंकि push_back()आपको लगता है कि यह हमेशा अंत में जोड़ देगा।
  2. कुछ कंटेनर भी संतुष्ट कर सकते हैं FrontInsertionSequenceऔर उनके पास है push_front। इससे संतुष्ट हैं deque, लेकिन द्वारा नहीं vector
  3. insert(x, ITERATOR)से है InsertionSequence, के लिए आम है जो setऔर vector। इस तरह आप setया तो vectorकई सम्मिलन के लिए लक्ष्य के रूप में उपयोग कर सकते हैं । हालाँकि, setइसके अतिरिक्त है insert(x), जो व्यावहारिक रूप से एक ही बात करता है (यह पहली प्रविष्टि में setइसका मतलब केवल एक अलग पुनरावृत्ति से शुरू करके उपयुक्त स्थान की खोज करना है - इस मामले में उपयोग नहीं की गई सुविधा)।

पिछले मामले के बारे में ध्यान दें कि यदि आप तत्वों को लूप में जोड़ने जा रहे हैं, तो वही काम करेंगे container.push_back(x)और container.insert(x, container.end())प्रभावी ढंग से करेंगे। हालांकि यह सच नहीं होगा यदि आप इसे container.end()पहले प्राप्त करते हैं और फिर पूरे लूप में इसका उपयोग करते हैं।

उदाहरण के लिए, आप निम्नलिखित कोड को जोखिम में डाल सकते हैं :

auto pe = v.end();
for (auto& s: a)
    v.insert(pe, v);

यह पूरी तरह aसे vवेक्टर में, रिवर्स ऑर्डर में पूरी तरह से कॉपी करेगा , और केवल तभी जब आप पर्याप्त भाग्यशाली होंगे कि विस्तार के लिए वेक्टर को वास्तविक रूप से प्राप्त न करें (आप reserve()पहले कॉल करके इसे रोक सकते हैं ); अगर आप इतने खुशकिस्मत नहीं हैं, तो आपको तथाकथित अनडिफ़ाइंड बिहेवियर (टीएम) मिलेगा। सैद्धांतिक रूप से इसकी अनुमति नहीं है क्योंकि वेक्टर के पुनरावृत्तियों को हर बार एक नया तत्व जोड़ने पर अमान्य माना जाता है।

यदि आप इसे इस प्रकार करते हैं:

copy(a.begin(), a.end(), back_inserter(v);

यह मूल क्रम aके अंत में कॉपी हो जाएगा v, और इससे पुनरावृत्ति अमान्य होने का खतरा नहीं है।

[संपादित करें] मैंने पहले इस कोड को इस तरह से बनाया था, और यह एक गलती थी क्योंकि inserterवास्तव में खुजली की वैधता और उन्नति को बनाए रखता है:

copy(a.begin(), a.end(), inserter(v, v.end());

तो यह कोड बिना किसी जोखिम के सभी तत्वों को मूल क्रम में भी जोड़ देगा।


एसटीडी :: आवेषण के बारे में आपकी टिप्पणी वेक्टर-जैसे कंटेनरों के लिए "जोखिम भरा" होना गलत है। वास्तव में, यह इन जोखिमों को खत्म करने के लिए बनाया गया है। कोई रिवर्स ऑर्डर नहीं, कोई अपरिभाषित व्यवहार नहीं। उदाहरण के लिए देखें विखंडन के लिए fluentcpp.com/2017/10/06/stl-inserter-iterators-work
डाउनहिलफ्रॉमेरे

आप सही हे। मैं इसे एक विस्तृत मैनुअल लूप में विस्तारित करने के बजाय कोड को छोटा बनाना चाहता था, इसलिए यह वास्तव में सच नहीं है क्योंकि inserterइट्रेटर की उन्नति और वैधता को बनाए रखता है। मुझे पोस्ट को संपादित करना होगा :)
एथोरिस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.