Std का हर मान रीसेट करने का सबसे तेज़ तरीका :: वेक्टर <int> को 0


198

std::vector<int>0 से प्रत्येक मान को रीसेट करने और वैक्टर को प्रारंभिक आकार में रखने का सबसे तेज़ तरीका क्या है ?

[] ऑपरेटर के साथ लूप के लिए?



1
प्रदर्शन में "सबसे तेज"? या लागू करने / बनाए रखने में सबसे आसान है?
thegeneral

जवाबों:


341
std::fill(v.begin(), v.end(), 0);

48
असेंबली आउटपुट को देखते हुए, gcc वास्तव में इस लूप को उस समय तक 16 बाइट्स में डंप करने के लिए mmx रजिस्टरों का उपयोग करने के लिए अंत तक करीब आने तक अनियंत्रित करता है। मैं कहूंगा कि यह बहुत तेज है। मेमसेट संस्करण याद करने के लिए कूदता है, जिसके बारे में मैं अनुमान लगा रहा हूं कि यह तेज है। मैं तुम्हारी विधि का उपयोग करूँगा।
सर्वव्यापी

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

2
यह ठीक वैसा नहीं है जैसा कि ओपी ने पूछा था, लेकिन बस अपने वेक्टर को उसी आकार के एक नए आकार में पुनः सौंपना ( v = std::vector<int>(vec_size,0)) fillमेरी मशीन पर थोड़ा तेज लगता है
Yibo Yang

1
यह इसे करने का सबसे मुहावरेदार तरीका है, उपयोग करने से अधिक मुहावरेदार assign
alfC

1
यह एक नया सदिश करने के लिए आवंटित करता है? और फिर मौजूदा वेक्टर के आवंटन को छोड़ दें? मैं देख सकता था कि मेम्ट एट अल
कॉनरेड जोन्स

150

हमेशा की तरह जब आप सबसे तेज़ के बारे में पूछते हैं: माप! उपरोक्त विधियों का उपयोग करना (एक मैक पर क्लैंग का उपयोग करके):

Method      |  executable size  |  Time Taken (in sec) |
            |  -O0    |  -O3    |  -O0      |  -O3     |  
------------|---------|---------|-----------|----------|
1. memset   | 17 kB   | 8.6 kB  | 0.125     | 0.124    |
2. fill     | 19 kB   | 8.6 kB  | 13.4      | 0.124    |
3. manual   | 19 kB   | 8.6 kB  | 14.5      | 0.124    |
4. assign   | 24 kB   | 9.0 kB  | 1.9       | 0.591    |

10000 ints के वेक्टर पर 100000 पुनरावृत्तियों का उपयोग करना।

संपादित करें: यदि इस संख्या को बदलने से परिणामी समय बदल जाता है तो आपको कुछ विश्वास हो सकता है (अंतिम विधानसभा कोड का निरीक्षण करने के लिए उतना अच्छा नहीं) कि कृत्रिम बेंचमार्क को पूरी तरह से अनुकूलित नहीं किया गया है। निश्चित रूप से वास्तविक परिस्थितियों में प्रदर्शन को गड़बड़ाना सबसे अच्छा है। अंत संपादित करें

उपयोग किए गए कोड के संदर्भ के लिए:

#include <vector>

#define TEST_METHOD 1
const size_t TEST_ITERATIONS = 100000;
const size_t TEST_ARRAY_SIZE = 10000;

int main(int argc, char** argv) {

   std::vector<int> v(TEST_ARRAY_SIZE, 0);

   for(size_t i = 0; i < TEST_ITERATIONS; ++i) {
   #if TEST_METHOD == 1 
      memset(&v[0], 0, v.size() * sizeof v[0]);
   #elif TEST_METHOD == 2
      std::fill(v.begin(), v.end(), 0);
   #elif TEST_METHOD == 3
      for (std::vector<int>::iterator it=v.begin(), end=v.end(); it!=end; ++it) {
         *it = 0;
      }
   #elif TEST_METHOD == 4
      v.assign(v.size(),0);
   #endif
   }

   return EXIT_SUCCESS;
}

निष्कर्ष: उपयोग std::fill(क्योंकि, जैसा कि दूसरों ने कहा है कि इसका सबसे मुहावरा है)!


3
+1। यह विशेष बेंचमार्क निर्णायक नहीं है, लेकिन यह बात बिल्कुल सही है, आपको विकल्पों का प्रदर्शन परीक्षण लिखना चाहिए क्योंकि वे वास्तव में उपयोग किए जाएंगे। यदि कोई प्रदर्शन अंतर नहीं है, तो जो भी सबसे सरल स्रोत है, का उपयोग करें।
स्टीव जेसोप

3
"... निर्णायक नहीं ..." IMO अपने आप में यह अनिश्चितता पहले से ही बेंचमार्क करने के लिए एक अच्छा बिंदु है, अधिक बार ऑप्टिमाइज़र पहले से ही नहीं करता है कि ओपी के बारे में किस तरह की स्थितियों के लिए एक बहुत अच्छा काम करता है। और मैं "अगर कोई महत्वपूर्ण प्रदर्शन अंतर नहीं है ..." पढ़ने के लिए आपके अंतिम वाक्य को संशोधित करेगा ...
Fabio Fracassi

4
अद्यतन का उपयोग करते हुए नउनियस मानक के लिए: clang3.6-libc ++ - c ++ 1 वर्ष-ओ 3 , gcc4.9-c ++ 1 वर्ष-ओ 3 और gcc5-c ++ 1 वर्ष-ओ 3 - टी एल; डॉ : assign, धीमी है छोटी क्षमताओं के अलावा पर है libc++। CODE कोलीरू / पेस्ट
sehe

2
इसके अलावा, वाह, यदि आप अनुकूलन के बिना गति के बारे में परवाह करते हैं (जो कि 'डिबग' मोड में तैनात है, तो कुछ लोग जो कर सकते हैं) प्रशंसनीय हो सकता है fill। यह इस परीक्षण में परिमाण धीमी करने के दो आदेश हैं
काइल स्ट्रैंड

5
@KyleStrand: ऐसा नहीं है कि भरना भयानक है, यह एक टेम्पलेट है और कोड आपके अनुवाद इकाई के अंदर -0 के साथ उत्पन्न होता है। जब आप मेमसेट का उपयोग करते हैं, तो आप उस libc कोड का उपयोग कर रहे हैं जिसे -O3 के साथ संकलित किया गया था (तब भी जब आप अपने कोड को -O0 के साथ संकलित करते हैं)। यदि आप डीबग में गति के बारे में परवाह करते हैं और आप टेम्प्लेट का उपयोग करते हैं, तो आपको एक अलग फाइल में स्पष्ट टेम्प्लेट इंस्टेंटेशन का उपयोग करना होगा जिसे आप -3 के साथ संकलित करते हैं
टिक

25

कैसे assignसदस्य समारोह के बारे में ?

some_vector.assign(some_vector.size(), 0);

2
ओपी मौजूदा मूल्यों को रीसेट करना चाहता था, लेकिन मूल्यों का आकार बदलने और रीसेट करने के लिए आपका जवाब बेहतर है। धन्यवाद!

15

यदि यह केवल पूर्णांक का वेक्टर है, तो मैं पहली बार कोशिश करूँगा:

memset(&my_vector[0], 0, my_vector.size() * sizeof my_vector[0]);

यह बहुत सी ++ नहीं है, इसलिए मुझे यकीन है कि कोई ऐसा करने का उचित तरीका प्रदान करेगा। :)


3
चूंकि मानक (2003 TC1) गारंटी देता है कि एक std :: वेक्टर स्मृति में सन्निहित है, यह ठीक होना चाहिए। यदि आपकी c ++ लाइब्रेरी 2003 TC1 के अनुरूप नहीं है, तो इसका उपयोग न करें।
मारियो

2
@Mario: मैंने इसे तब तक पोस्ट नहीं किया था जब तक कि यह सच नहीं था और इसे अच्छी तरह से जाना जाता था। :) लेकिन धन्यवाद।
खोलना

1
मैंने विधानसभा की जाँच की। ::std::fillविधि, कुछ है कि बहुत तेजी से रफ़ू है करने के लिए फैलता है, हालांकि, क्योंकि यह सब इनलाइन है कोड-bloaty पक्ष पर एक सा। मैं अभी भी इसका उपयोग करूँगा, क्योंकि यह पढ़ने के लिए बहुत अच्छा है।
सर्वव्यापी

4
यदि वेक्टर खाली है और आप इस मामले में कुछ नहीं करते हैं, तो आपको चेक जोड़ना बेहतर होगा। खाली वेक्टर के लिए गणना और बफ़ [0] एसटीएल कोड में दावे उत्पन्न कर सकता है।
सर्गेई

4

प्रयत्न

std::fill

और भी

std::size siz = vec.size();
//no memory allocating
vec.resize(0);
vec.resize(siz, 0);

आकार बहुत अच्छा है
निक

3

मेरे पास एक ही सवाल था, लेकिन इसके बारे में कम vector<bool>(afaik मानक इसे आंतरिक रूप से केवल बूलियन तत्वों के एक निरंतर सरणी की तुलना में अलग तरीके से लागू करने की अनुमति देता है)। इसलिए मैंने फैबियो फ्रैकासी द्वारा थोड़ा संशोधित परीक्षण दोहराया। परिणाम इस प्रकार हैं (समय, सेकंड में):

            -O0       -O3
         --------  --------
memset     0.666     1.045
fill      19.357     1.066
iterator  67.368     1.043
assign    17.975     0.530
for i     22.610     1.004

तो जाहिर है इन आकारों के लिए, vector<bool>::assign()तेज है। परीक्षणों के लिए उपयोग किया जाने वाला कोड:

#include <vector>
#include <cstring>
#include <cstdlib>

#define TEST_METHOD 5
const size_t TEST_ITERATIONS = 34359738;
const size_t TEST_ARRAY_SIZE = 200;

using namespace std;

int main(int argc, char** argv) {

    std::vector<int> v(TEST_ARRAY_SIZE, 0);

    for(size_t i = 0; i < TEST_ITERATIONS; ++i) {
#if TEST_METHOD == 1
        memset(&v[0], false, v.size() * sizeof v[0]);
#elif TEST_METHOD == 2
        std::fill(v.begin(), v.end(), false);
   #elif TEST_METHOD == 3
        for (std::vector<int>::iterator it=v.begin(), end=v.end(); it!=end; ++it) {
            *it = 0;
        }
   #elif TEST_METHOD == 4
      v.assign(v.size(),false);
   #elif TEST_METHOD == 5
      for (size_t i = 0; i < TEST_ARRAY_SIZE; i++) {
          v[i] = false;
      }
#endif
    }

    return EXIT_SUCCESS;
}

मैंने Ubuntu 17.10 पर GCC 7.2.0 संकलक का उपयोग किया। संकलन के लिए कमांड लाइन:

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