सरणियों या std का उपयोग करना :: C ++ में वैक्टर, प्रदर्शन अंतर क्या है?


208

हमारे C ++ पाठ्यक्रम में वे नए प्रोजेक्ट्स पर C ++ सरणियों का उपयोग नहीं करने का सुझाव देते हैं। जहां तक ​​मैं जानता हूं कि स्ट्रॉस्टग्रुप खुद ही सरणियों का उपयोग नहीं करने का सुझाव देता है। लेकिन क्या महत्वपूर्ण प्रदर्शन अंतर हैं?


2
आप क्यों सोचेंगे कि एक प्रदर्शन अंतर है।
मार्टिन न्यूयॉर्क

99
क्योंकि आमतौर पर बेहतर कार्यक्षमता के साथ सबसे खराब प्रदर्शन आता है।
तुन्नुज

19
मैं समय से पहले अनुकूलन के बारे में सहमत हूं, लेकिन बेहतर भंडारण पद्धति का चयन करना बहुत मायने रखता है। अक्सर वास्तविक दुनिया में कोड को भेजना पड़ता है और अगला उत्पाद विकसित होता है और अनुकूलन कदम कभी नहीं होता है।
चींटी

132
काश लोग चिल्लाते "समय से पहले अनुकूलन बंद कर देते!" जब भी कोई प्रदर्शन से संबंधित एक सरल प्रश्न पूछ रहा है! सवाल का जवाब दें और सिर्फ PREMATURELY न मानें कि लोग समय से पहले कुछ भी कर रहे हैं।
d7samurai

4
@ d7samaurai: सहमत हूं, मैंने अभी तक किसी को भी कोशिश करते हुए नहीं देखा हैint main(int argc, const std::vector<string>& argv)
मार्क के कोवान

जवाबों:


189

C ++ सरणियों का उपयोग new(यानी डायनेमिक सरणियों का उपयोग करके) से बचना चाहिए। समस्या यह है कि आपको आकार का ट्रैक रखना है, और आपको उन्हें मैन्युअल रूप से हटाने और सभी प्रकार की हाउसकीपिंग करने की आवश्यकता है।

स्टैक पर सरणियों का उपयोग करना भी हतोत्साहित किया जाता है क्योंकि आपके पास रेंज चेकिंग नहीं है, और आस-पास सरणी को पास करने से इसके आकार के बारे में कोई भी जानकारी खो जाएगी (सरणी से सूचक रूपांतरण)। आपको boost::arrayउस मामले में उपयोग करना चाहिए , जो एक छोटी कक्षा में C ++ सरणी लपेटता है sizeऔर उस पर पुनरावृति करने के लिए एक फ़ंक्शन और पुनरावृत्तियों प्रदान करता है।

अब std :: वेक्टर बनाम देशी C ++ सरणियाँ (इंटरनेट से ली गई):

// Comparison of assembly code generated for basic indexing, dereferencing, 
// and increment operations on vectors and arrays/pointers.

// Assembly code was generated by gcc 4.1.0 invoked with  g++ -O3 -S  on a 
// x86_64-suse-linux machine.

#include <vector>

struct S
{
  int padding;

  std::vector<int> v;
  int * p;
  std::vector<int>::iterator i;
};

int pointer_index (S & s) { return s.p[3]; }
  // movq    32(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

int vector_index (S & s) { return s.v[3]; }
  // movq    8(%rdi), %rax
  // movl    12(%rax), %eax
  // ret

// Conclusion: Indexing a vector is the same damn thing as indexing a pointer.

int pointer_deref (S & s) { return *s.p; }
  // movq    32(%rdi), %rax
  // movl    (%rax), %eax
  // ret

int iterator_deref (S & s) { return *s.i; }
  // movq    40(%rdi), %rax
  // movl    (%rax), %eax
  // ret

// Conclusion: Dereferencing a vector iterator is the same damn thing 
// as dereferencing a pointer.

void pointer_increment (S & s) { ++s.p; }
  // addq    $4, 32(%rdi)
  // ret

void iterator_increment (S & s) { ++s.i; }
  // addq    $4, 40(%rdi)
  // ret

// Conclusion: Incrementing a vector iterator is the same damn thing as 
// incrementing a pointer.

नोट: यदि आप किसी उपयोगकर्ता परिभाषित कंस्ट्रक्टर के बिना सरणियों को आवंटित करते हैं newऔर गैर-श्रेणी की वस्तुओं (जैसे सादे int) या कक्षाओं को आवंटित करते हैं और आप अपने तत्वों को शुरू में शुरू नहीं करना चाहते हैं, तो new-लेक्टेड सरणियों के उपयोग से प्रदर्शन लाभ हो सकते हैं क्योंकि std::vectorसभी तत्वों को प्रारंभिक करता है डिफ़ॉल्ट मान (0 उदाहरण के लिए, निर्माण पर) (मुझे याद दिलाने के लिए @bernie को क्रेडिट)।


77
लानत एटी एंड टी सिंटैक्स का आविष्कार किसने किया था? केवल अगर मैं जानता था ... :)
मेहरदाद अफश्री

4
यह दृश्य C ++ कंपाइलर के लिए सही नहीं है। लेकिन जीसीसी के लिए यह है।
टोटो

5
मेरा उत्तर में कहना है कि वेक्टर नहीं करता है है सूचक संचालन correponding की तुलना में धीमी होने के लिए। बेशक, यह कर सकते हैं (आसान डिबग मोड, भी सक्षम सक्षम करने से प्राप्त करने के लिए) :) हो
litb - Johannes Schaub

18
+1 के लिए "एक सदिश अनुक्रमणिका एक सूचक को अनुक्रमणित करने के समान समान है।" और अन्य निष्कर्ष के लिए भी।
नवाज

3
@ Piotr99 मैं आपसे बहस नहीं करने जा रहा हूं, लेकिन जब आप उच्च स्तर की भाषाएं सीखने के बाद असेंबली सीखते हैं, तो इंटेल सिंटैक्स सिर्फ कुछ पीछे की ओर से बहुत अधिक समझ में आता है, उपसर्ग (संख्या), प्रत्यय (निर्देश), और अस्पष्ट (एक्सेस करने वाली मेमोरी) ) एटी एंड टी सिंटैक्स की प्रकृति।
कोल जॉनसन

73

सूक्ष्म-आशावादी लोगों के लिए प्रस्तावना

याद है:

"प्रोग्रामर अपने कार्यक्रमों के गैर-राजनीतिक भागों की गति के बारे में सोचने या चिंता करने में बहुत समय बर्बाद करते हैं, और दक्षता पर इन प्रयासों का वास्तव में एक मजबूत नकारात्मक प्रभाव पड़ता है जब डिबगिंग और रखरखाव पर विचार किया जाता है। हमें छोटी क्षमता के बारे में भूलना चाहिए, इस बारे में कहना चाहिए। समय का 97%: समयपूर्व अनुकूलन सभी बुराई की जड़ है। फिर भी हमें उस महत्वपूर्ण 3% में अपने अवसरों को पारित नहीं करना चाहिए।

( पूर्ण उद्धरण के लिए कायापलट के लिए धन्यवाद )

एक वेक्टर (या जो भी) के बजाय एक सी सरणी का उपयोग न करें क्योंकि आप मानते हैं कि यह तेज़ है क्योंकि यह निचले स्तर का माना जाता है। आप गलत होंगे।

डिफ़ॉल्ट वेक्टर (या आपकी ज़रूरत के अनुसार सुरक्षित कंटेनर) का उपयोग करें, और फिर यदि आपका प्रोफाइलर कहता है कि यह एक समस्या है, तो देखें कि क्या आप इसे बेहतर एल्गोरिथ्म का उपयोग करके, या कंटेनर बदलकर कर सकते हैं।

इसने कहा, हम मूल प्रश्न पर वापस जा सकते हैं।

स्थिर / गतिशील सरणी?

C ++ सरणी वर्ग को निम्न-स्तरीय C सरणी से बेहतर व्यवहार किया जाता है क्योंकि वे अपने बारे में बहुत कुछ जानते हैं, और उन प्रश्नों का उत्तर दे सकते हैं जो C सरणियाँ नहीं कर सकती हैं। वे खुद के बाद साफ करने में सक्षम हैं। और अधिक महत्वपूर्ण बात, वे आमतौर पर टेम्प्लेट और / या इनलाइनिंग का उपयोग करके लिखे जाते हैं, जिसका अर्थ है कि डिबग में बहुत सारे कोड दिखाई देते हैं जो रिलीज बिल्ड में कम या कोई कोड नहीं होता है, जिसका अर्थ है कि उनके अंतर्निहित कम सुरक्षित प्रतिस्पर्धा से कोई अंतर नहीं है।

सभी में, यह दो श्रेणियों पर पड़ता है:

गतिशील सरणियाँ

एक मॉलॉक-एड / न्यू-एड सरणी के लिए एक पॉइंटर का उपयोग करना सबसे अच्छा होगा जितनी तेजी से स्टैड :: वेक्टर संस्करण, और बहुत कम सुरक्षित ( लिटब के पोस्ट देखें )।

तो एक std :: वेक्टर का उपयोग करें।

स्थैतिक सरणियाँ

एक स्थिर सरणी का उपयोग करना सबसे अच्छा होगा:

  • जितनी तेजी से std :: सरणी संस्करण
  • और बहुत कम सुरक्षित है।

इसलिए एक std :: array का इस्तेमाल करें ।

अनधिकृत स्मृति

vectorकच्चे बफर के बजाय कभी-कभी एक दृश्यमान लागत का उपयोग किया जाता है, क्योंकि vectorनिर्माण में बफर को इनिशियलाइज़ करेगा, जबकि कोड ने इसे प्रतिस्थापित नहीं किया, जैसा कि उसके जवाब में बर्नी ने कहा था ।

यदि यह मामला है, तो आप इसे या के unique_ptrबजाय का उपयोग करके इसे संभाल सकते हैं vector, यदि मामला आपके कोडलाइन में असाधारण नहीं है, तो वास्तव में एक वर्ग लिखें जो buffer_ownerउस मेमोरी का मालिक होगा, और आपको इसे आसान और सुरक्षित एक्सेस प्रदान करेगा, जिसमें शामिल हैं बोनस का आकार बदलना (उपयोग करना realloc?), या जो भी आपको चाहिए।


1
स्थैतिक सरणियों को संबोधित करने के लिए धन्यवाद - std :: वेक्टर बेकार है यदि आपको प्रदर्शन कारणों से गतिशील रूप से स्मृति आवंटित करने की अनुमति नहीं है।
टॉम

10
जब आप कहते हैं "स्थैतिक सरणी का उपयोग करना तेजी से बढ़ावा देने के रूप में सबसे अच्छा होगा :: सरणी संस्करण" यह दर्शाता है कि आप कितने पक्षपाती हैं। यह चारों ओर अन्य होना चाहिए, बूस्ट: सरणी स्थिर सरणियों की तरह सबसे तेजी से हो सकती है।
टोटो

3
@ टोटो: यह एक गलतफहमी है: आपको इसे "एक स्थिर सरणी का उपयोग करना सबसे अच्छा होगा (जैसा कि तेजी से बढ़ावा :: सरणी संस्करण) && (बहुत कम सुरक्षित)) के रूप में पढ़ना चाहिए"। मैं यह स्पष्ट करने के लिए पोस्ट को संपादित करूँगा। वैसे, संदेह के लाभ के लिए धन्यवाद।
पियरसबल

1
std :: array के बारे में क्या?
पॉलम

4
हमेशा पूरी बोली दिखाते हैं। "प्रोग्रामर अपने कार्यक्रमों के गैर-राजनीतिक भागों की गति के बारे में सोचने या चिंता करने में बहुत समय बर्बाद करते हैं, और दक्षता पर इन प्रयासों का वास्तव में एक मजबूत नकारात्मक प्रभाव पड़ता है जब डिबगिंग और रखरखाव पर विचार किया जाता है। हमें छोटी क्षमता के बारे में भूलना चाहिए, इस बारे में कहना चाहिए। समय का 97%: समय से पहले अनुकूलन सभी बुराई की जड़ है। फिर भी हमें उस महत्वपूर्ण 3% में अपने अवसरों को पारित नहीं करना चाहिए। " अन्यथा यह एक अर्थहीन साउंडबाइट बन जाता है।
मेटामॉर्फोसिस

32

वैक्टर हुड के नीचे सरणियाँ हैं। प्रदर्शन वही है।

एक जगह जहां आप एक प्रदर्शन के मुद्दे में भाग सकते हैं, वेक्टर को सही तरीके से शुरू करने के लिए नहीं कर रहा है।

जैसा कि एक वेक्टर भर जाता है, यह खुद को आकार देगा, और इसका मतलब यह हो सकता है कि एक नया सरणी आवंटन, उसके बाद n कॉपी कंस्ट्रक्टर्स, उसके बाद n डिस्ट्रक्टर कॉल, उसके बाद एक सरणी डिलीट।

यदि आपका निर्माण / विनाश महंगा है, तो आप वेक्टर को शुरू करने के लिए सही आकार बनाने से बहुत बेहतर हैं।

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


4
लटकन: प्रदर्शन में एक ही बड़ा O. std है :: वेक्टर थोड़ा सा बहीखाता करता है, जो संभवतः थोड़ी मात्रा में खर्च होता है। OTOH, आप अपने स्वयं के गतिशील सरणियों को रोल करते समय एक ही बहीखाता पद्धति के बहुत कुछ करते हैं।
dmckee --- पूर्व-मध्यस्थ ने

हाँ मैं समझता हूँ। उनके सवाल का जोर हालांकि, प्रदर्शन अंतर क्या थे ..... मैंने इस पर ध्यान देने का प्रयास किया।
EvilTeach

Gcc का std :: वेक्टर वास्तव में क्षमता को एक-एक करके बढ़ाता है यदि आप पुश_बैक कहते हैं।
bjhend

3
@bjhend फिर gcc की std::vectorध्वनियाँ मानकों-गैर-अनुरूप हैं? मेरा मानना ​​है कि मानक की आवश्यकता है कि vector::push_backलगातार जटिलता बढ़ गई है, और प्रत्येक पर 1 से बढ़ती क्षमता push_backreallocs के लिए खाते के बाद n ^ 2 जटिलता हो रही है। - किसी प्रकार की घातीय क्षमता में वृद्धि होने पर push_backऔर insert, reserveसदिश सामग्री प्रतियों में सबसे स्थिर कारक वृद्धि के लिए नेतृत्व करने में विफलता होगी। यदि आप असफल रहे तो 1.5 घातीय वेक्टर ग्रोथ फैक्टर का अर्थ ~ 3x जितनी प्रतियाँ होंगी reserve()
यक्क - एडम नेवरामॉन्ट

3
@bjhend आप गलत हैं। मानक वृद्धि घातीय वृद्धि को रोकती है: .3 23.2.3 पैरा 16 कहता है "तालिका 101 ऐसे संचालन को सूचीबद्ध करती है जो कुछ प्रकार के अनुक्रम कंटेनरों के लिए प्रदान किए जाते हैं, लेकिन अन्य नहीं। एक कार्यान्वयन" कंटेनर "कॉलम में दिखाए गए सभी कंटेनर प्रकारों के लिए ये संचालन प्रदान करेगा, और उन्हें लागू करने के लिए इतनी के रूप में लगातार समय बढ़ जाएगा। " (तालिका 101 इसमें पुश_बैक वाली है)। अब कृपया FUD फैलाना बंद करें। कोई भी मुख्यधारा का कार्यान्वयन इस आवश्यकता का उल्लंघन नहीं करता है। Microsoft का मानक C ++ पुस्तकालय 1.5x कारक के साथ बढ़ता है, और GCC 2x कारक के साथ बढ़ता है।
आर। मार्टिनो फर्नांडिस

27

कुछ जवाब के लिए मेहरदाद ने कहा:

हालांकि, ऐसे मामले भी हो सकते हैं जहां आपको अभी भी सरणियों की आवश्यकता है। निम्न स्तर कोड (यानी असेंबली) या पुराने पुस्तकालयों के साथ इंटरफेस करने के लिए, जिसमें सरणियों की आवश्यकता होती है, आप वैक्टर का उपयोग करने में सक्षम नहीं हो सकते हैं।

सच नहीं है। यदि आप उपयोग करते हैं तो वैक्टर सरणियों / बिंदुओं में अच्छी तरह से नीचा दिखाते हैं:

vector<double> vector;
vector.push_back(42);

double *array = &(*vector.begin());

// pass the array to whatever low-level code you have

यह सभी प्रमुख एसटीएल कार्यान्वयनों के लिए काम करता है। अगले मानक में, इसे काम करने की आवश्यकता होगी (भले ही यह आज ठीक हो)।


1
वर्तमान मानक ऐसी कोई बात नहीं कहता है। यह निहित है, और इसे निरंतर भंडारण के रूप में लागू किया जाता है। लेकिन मानक केवल यह कहता है कि यह एक यादृच्छिक एक्सेस कंटेनर (पुनरावृत्तियों का उपयोग करके) है। अगला मानक स्पष्ट होगा।
फ्रैंक क्रुएगर

1
& * v.begin () केवल पुनरावृत्तिकर्ता के परिणाम के लिए & ऑपरेटर लागू करता है। डी-रेफरेंसिंग किसी भी प्रकार की वापसी कर सकता है। एड्रेस-इन ऑपरेटर के उपयोग से फिर से किसी भी प्रकार की वापसी हो सकती है। मानक इसे पॉइंटर के रूप में मेमोरी के एक सन्निहित क्षेत्र में परिभाषित नहीं करता है।
फ्रैंक क्रुएगर

15
मूल रूप से 1998 के मूल पाठ को वास्तव में इसकी आवश्यकता नहीं थी, लेकिन 2003 में एक परिशिष्ट था जो इसे संबोधित करता है, इसलिए यह वास्तव में मानक द्वारा कवर किया गया है। जड़ी
Nemanja Trifunovic

2
C ++ 03 में स्पष्ट रूप से कहा गया &v[n] == &v[0] + nहै कि प्रदान nकी गई वैधता आकार सीमा के भीतर है। इस कथन वाला पैराग्राफ C ++ 11 के साथ नहीं बदला।
bjhend

2
सिर्फ std :: वेक्टर :: डेटा () का उपयोग क्यों नहीं किया जाता है?
पल्म

15

आपके पास C ++ 11 में सादे सरणियों का उपयोग करने के लिए और भी कम कारण हैं।

प्रकृति में सबसे तेजी से धीमी गति से 3 प्रकार के सरणियों हैं, उनके पास सुविधाओं के आधार पर (निश्चित रूप से कार्यान्वयन की गुणवत्ता सूची में मामले 3 के लिए भी चीजें वास्तव में तेजी से बना सकती हैं):

  1. संकलन समय पर ज्ञात आकार के साथ स्थिर। ---std::array<T, N>
  2. रनटाइम पर ज्ञात आकार के साथ गतिशील और कभी भी आकार नहीं बदला गया। यहाँ विशिष्ट अनुकूलन यह है कि यदि सरणी को सीधे स्टैक में आवंटित किया जा सकता है। - उपलब्ध नहीं । शायदdynarray C ++ 14 के बाद C ++ TS में। C में VLAs हैं
  3. रनटाइम पर गतिशील और आकार बदलने योग्य। ---std::vector<T>

के लिए 1. तत्वों की निश्चित संख्या, उपयोग के साथ सादे स्थिर सरणियोंstd::array<T, N> सी ++ 11 में।

के लिए 2। तय आकार कार्यावधि में निर्दिष्ट सरणियों, लेकिन वह उनके आकार में परिवर्तन नहीं होगा, वहाँ सी में चर्चा है ++ 14 लेकिन यह एक तकनीकी विनिर्देश में ले जाया गया और अंत में सी के ++ 14 बाहर कर दिया गया है।

के लिए 3. std::vector<T> आमतौर पर ढेर में स्मृति के लिए पूछेंगे । इसके प्रदर्शन के परिणाम हो सकते हैं, हालांकि आप std::vector<T, MyAlloc<T>>कस्टम आवंटनकर्ता के साथ स्थिति को बेहतर बनाने के लिए उपयोग कर सकते हैं । इसकी तुलना में लाभ यह T mytype[] = new MyType[n];है कि आप इसका आकार बदल सकते हैं और यह एक सूचक को क्षय नहीं करेगा, जैसा कि सादे सरणियां करते हैं।

संकेत करने के लिए क्षय से बचने के लिए उल्लिखित मानक पुस्तकालय प्रकारों का उपयोग करें । आप डिबगिंग के समय को बचाएंगे और प्रदर्शन बिल्कुल वैसा ही है जैसा कि यदि आप समान सुविधाओं के सेट का उपयोग करते हैं।


2
std :: dynarray। n3690 के लिए राष्ट्रीय निकाय टिप्पणियों की समीक्षा के बाद, इस लाइब्रेरी घटक को C ++ 14 वर्किंग पेपर से एक अलग तकनीकी विनिर्देश में वोट दिया गया था। यह कंटेनर n3797 के रूप में मसौदा C ++ 14 का हिस्सा नहीं है। en.cppreference.com/w/cpp/container/dynarray
मोहम्मद अल-

1
बहुत अच्छा जवाब। संक्षिप्त और सारांश, अभी तक किसी भी से अधिक विवरण।
मोहम्मद अल-नकीब

6

एसटीएल के साथ जाओ। कोई प्रदर्शन दंड नहीं है। एल्गोरिदम बहुत कुशल हैं और वे उन प्रकार के विवरणों को संभालने का एक अच्छा काम करते हैं जिनके बारे में हम में से अधिकांश ने नहीं सोचा होगा।


5

एसटीएल एक भारी अनुकूलित पुस्तकालय है। वास्तव में, यह उन खेलों में भी एसटीएल का उपयोग करने का सुझाव दिया गया है जहाँ उच्च प्रदर्शन की आवश्यकता हो सकती है। Arrays बहुत अधिक त्रुटि है, जिसका उपयोग दिन-प्रतिदिन के कार्यों में किया जाता है। आज के कंपाइलर भी बहुत स्मार्ट हैं और वास्तव में एसटीएल के साथ उत्कृष्ट कोड का उत्पादन कर सकते हैं। यदि आप जानते हैं कि आप क्या कर रहे हैं, तो एसटीएल आमतौर पर आवश्यक प्रदर्शन प्रदान कर सकता है। उदाहरण के लिए वैक्टर को आवश्यक आकार से शुरू करना (यदि आप शुरू से जानते हैं), तो आप मूल रूप से सरणी प्रदर्शन प्राप्त कर सकते हैं। हालांकि, ऐसे मामले भी हो सकते हैं जहां आपको अभी भी सरणियों की आवश्यकता है। निम्न स्तर कोड (यानी असेंबली) या पुराने पुस्तकालयों के साथ इंटरफेस करने के लिए, जिसमें सरणियों की आवश्यकता होती है, आप वैक्टर का उपयोग करने में सक्षम नहीं हो सकते हैं।


4
यह देखते हुए कि वेक्टर सन्निहित है, अभी भी पुस्तकालयों के साथ इंटरफ़ेस करना बहुत आसान है जिसमें सरणियों की आवश्यकता होती है।
ग्रेग रोजर्स

हां, लेकिन अगर आप वेक्टर के आंतरिक सामान के साथ गड़बड़ करना चाहते हैं, तो वेक्टर का उपयोग करने में कम लाभ होगा। वैसे, कीवर्ड "नहीं हो सकता है।"
मेहरदाद अफश्री

3
केवल एक ही मामला है जो मुझे पता है कि कहाँ वैक्टर का उपयोग नहीं किया जा सकता है: यदि आकार 0. है तो & [a] या * a.begin () काम नहीं करेगा। c ++ 1x ठीक करेगा कि a.data () फ़ंक्शन को शुरू करने के साथ जो तत्वों को रखते हुए आंतरिक बफ़र लौटाता है
जोहान्स स्कहब - litb

मेरे दिमाग में विशिष्ट परिदृश्य जब मैंने लिखा था कि स्टैक-आधारित सरणियाँ थीं।
मेहरदाद आफश्री

1
सदिश या किसी भी सन्निहित कंटेनर को C के साथ: vec.data()डेटा के लिए और vec.size()आकार के लिए। इट्स दैट ईजी।
जर्मन डियागो

5

दुली के योगदान के बारे में

निष्कर्ष यह है कि पूर्णांकों के ऐरे पूर्णांक के वैक्टर (मेरे उदाहरण में 5 गुना) से अधिक तेज हैं। हालाँकि, सरणियाँ और वैक्टर अधिक जटिल / संरेखित डेटा के लिए समान गति से घेरे रहते हैं।


3

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

अनुकूलित मोड में, मैं stl वेक्टर से किसी सरणी की दक्षता के लिए संपर्क करने की अपेक्षा करूंगा। यह तब से है क्योंकि कई वेक्टर विधियां अब अंतर्निर्मित हैं।


यह उल्लेख करना महत्वपूर्ण है। डीबग एसटीएल सामान की रूपरेखा बहुत धीमी है। और यह एक कारण है कि लोग एसटीएल को धीमा करते हैं।
एरिक एरोनिटी

3

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

C ++ कल्पना के लिए std:vectorनिर्माता एक लेने countतर्क (यह तीसरा रूप है) कहता है:

`विभिन्न डेटा स्रोतों से एक नए कंटेनर का निर्माण करता है, वैकल्पिक रूप से उपयोगकर्ता द्वारा आपूर्ति किए गए आवंटन आवंटित का उपयोग करता है।

3) कंटेनर को T की कोई डिफ़ॉल्ट रूप से सम्मिलित आवृत्तियों के साथ निर्मित करता है। कोई प्रतिलिपि नहीं बनाई गई है।

जटिलता

2-3) रैखिक गिनती में

एक कच्ची सरणी इस आरंभीकरण लागत को भड़काती नहीं है।

यह भी देखें कि मैं अपने सभी तत्वों को इनिशियलाइज़ करने के लिए std :: वेक्टर <> से कैसे बच सकता हूँ?


2

दोनों के बीच प्रदर्शन अंतर बहुत अधिक कार्यान्वयन पर निर्भर है - यदि आप एक बुरी तरह से लागू किए गए std :: वेक्टर की तुलना एक इष्टतम सरणी कार्यान्वयन से करते हैं, तो सरणी जीत जाएगी, लेकिन इसे चारों ओर मोड़ दें और वेक्टर जीत जाएगा ...

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

उस ने कहा, IMHO वेक्टर एक डीबग STL के साथ डिबग परिदृश्य में जीतता है क्योंकि एक उचित डिबग मोड के साथ अधिकांश STL कार्यान्वयन कम से कम मानक कंटेनरों के साथ काम करते समय लोगों द्वारा की गई विशिष्ट गलतियों को उजागर / कैश कर सकते हैं।

ओह, और यह मत भूलो कि सरणी और वेक्टर एक ही मेमोरी लेआउट साझा करते हैं ताकि आप वैक्टर का उपयोग डेटा को विरासत सी या सी ++ कोड को पारित करने के लिए कर सकें जो मूल सरणियों की अपेक्षा करता है। ध्यान रखें कि अधिकांश दांव उस परिदृश्य में बंद हैं, हालांकि, और आप फिर से कच्ची मेमोरी के साथ काम कर रहे हैं।


1
मुझे लगता है कि प्रदर्शन की आवश्यकताओं को पूरा करने के लिए (ओ (1) लुकअप और सम्मिलन), आप लगभग है std :: वेक्टर <> गतिशील सरणियों का उपयोग कर लागू करने के लिए। निश्चित रूप से यह ऐसा करने का स्पष्ट तरीका है।
dmckee --- पूर्व मध्यस्थ ने

न केवल प्रदर्शन की आवश्यकताएं, बल्कि आवश्यकता है कि सन्निहित में भंडारण। एक खराब वेक्टर कार्यान्वयन सरणी और एपीआई के बीच अप्रत्यक्ष की कई परतें डाल देगा। एक अच्छा वेक्टर कार्यान्वयन
इनलाइन

वर्णित के रूप में एक खराब वेक्टर कार्यान्वयन मानक के अनुरूप नहीं होगा। यदि आप अप्रत्यक्ष चाहते हैं, तो std::dequeइसका इस्तेमाल किया जा सकता है।
फिल

1

यदि आपको आकार को गतिशील रूप से समायोजित करने की आवश्यकता नहीं है, तो आपके पास क्षमता (एक सूचक / size_t) को सहेजने की मेमोरी ओवरहेड है। बस।


1

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

मुझे आश्चर्य है कि किसी ने भी अभी तक इसका उल्लेख नहीं किया है - प्रदर्शन के बारे में चिंता न करें जब तक यह एक समस्या साबित नहीं हुई है, फिर बेंचमार्क।


1

मेरा तर्क है कि प्राथमिक चिंता प्रदर्शन नहीं है, लेकिन सुरक्षा है। आप सरणियों के साथ बहुत सी गलतियाँ कर सकते हैं (उदाहरण के लिए, आकार बदलने पर विचार करें), जहाँ एक वेक्टर आपको बहुत दर्द से बचाएगा।


1

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


2
यदि यह मायने रखता है, तो आप स्पष्ट रूप से गतिशील आकार के सरणियों का उपयोग नहीं कर रहे हैं, और जैसे, आपके सरणियों को आकार बदलने की आवश्यकता नहीं है। (अगर उन्होंने किया, तो आप आकार को किसी भी तरह स्टोर करेंगे)। इसलिए, जब तक मैं गलत नहीं हूँ, तब तक आप बढ़ावा देने के साथ-साथ सरणी का उपयोग कर सकते हैं - और आप क्या कहते हैं कि कहीं "आकार" स्टोर करने की आवश्यकता है?
अराफंगियन

1

निम्नलिखित सरल परीक्षण:

C ++ सरणी बनाम वेक्टर प्रदर्शन परीक्षण विवरण

"अनुक्रमणिका, बेसिक अनुक्रमण, डीरेफेरेंसिंग और वैक्टर और एरे / पॉइंटर्स पर वेतन वृद्धि के संचालन के लिए उत्पन्न विधानसभा कोड की तुलना" के निष्कर्षों का खंडन करता है।

सरणियों और वैक्टर के बीच अंतर होना चाहिए। परीक्षण कहता है ... बस कोशिश करो, कोड वहाँ है ...


1

कभी-कभी सरणियां वास्तव में वैक्टर से बेहतर होती हैं। यदि आप हमेशा ऑब्जेक्ट की एक निश्चित लंबाई सेट में हेरफेर कर रहे हैं, तो सरणियाँ बेहतर हैं। निम्नलिखित कोड स्निपेट पर विचार करें:

int main() {
int v[3];
v[0]=1; v[1]=2;v[2]=3;
int sum;
int starttime=time(NULL);
cout << starttime << endl;
for (int i=0;i<50000;i++)
for (int j=0;j<10000;j++) {
X x(v);
sum+=x.first();
}
int endtime=time(NULL);
cout << endtime << endl;
cout << endtime - starttime << endl;

}

जहाँ X का वेक्टर संस्करण है

class X {
vector<int> vec;
public:
X(const vector<int>& v) {vec = v;}
int first() { return vec[0];}
};

और एक्स का सरणी संस्करण है:

class X {
int f[3];

public:
X(int a[]) {f[0]=a[0]; f[1]=a[1];f[2]=a[2];}
int first() { return f[0];}
};

मुख्य () का सरणी संस्करण तेज़ होगा क्योंकि हम आंतरिक लूप में हर बार "नए" के ओवरहेड से बच रहे हैं।

(यह कोड मेरे द्वारा comp.lang.c ++ को पोस्ट किया गया था)।


1

यदि आप मल्टी-आयामी व्यवहार का प्रतिनिधित्व करने के लिए वैक्टर का उपयोग कर रहे हैं, तो एक प्रदर्शन हिट है।

क्या 2d + वैक्टर के कारण कोई प्रदर्शन प्रभावित होता है?

सार यह है कि प्रत्येक उप-वेक्टर में आकार की जानकारी के साथ थोड़ी सी ओवरहेड होती है, और आवश्यक रूप से डेटा का क्रमिककरण नहीं होगा (जैसा कि बहुआयामी सी सरणियों के साथ है)। यह क्रमबद्धता की कमी सूक्ष्म अनुकूलन अवसरों से अधिक की पेशकश कर सकती है। यदि आप बहुआयामी सरणियाँ कर रहे हैं, तो यह सिर्फ std :: वेक्टर का विस्तार करने के लिए सबसे अच्छा हो सकता है और अपने स्वयं के गेट / सेट / बिट्स फ़ंक्शन को आकार दे सकता है।


0

एक निश्चित लंबाई सरणी मान लिया जाये कि (जैसे int* v = new int[1000];बनाम std::vector<int> v(1000);, के आकार के साथ v1000 में तय रखा जा रहा है), केवल प्रदर्शन विचार यह है कि वास्तव में मायने रखती है (या जब मैं एक ऐसी ही दुविधा में था मेरे लिए मायने रखता कम से कम) एक के लिए उपयोग की गति है तत्व। मैंने एसटीएल के वेक्टर कोड को देखा, और यहां मैंने पाया है:

const_reference
operator[](size_type __n) const
{ return *(this->_M_impl._M_start + __n); }

यह फ़ंक्शन कंपाइलर द्वारा निश्चित रूप से इनलाइन होगा। इसलिए, जब तक कि केवल एक चीज जिसे आप करने की योजना बनाते हैं , vउसके तत्वों तक पहुंच है operator[], ऐसा लगता है कि प्रदर्शन में वास्तव में कोई अंतर नहीं होना चाहिए।

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