Cara tercepat untuk mengatur ulang setiap nilai std :: vector <int> ke 0


Jawaban:


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

48
Melihat output perakitan, gcc sebenarnya membuka gulungan lingkaran ini untuk menggunakan register mmx untuk membuang dalam 16 byte pada suatu waktu sampai mendekati akhir. Saya katakan itu cukup cepat. Versi memset melompat ke memset, yang saya kira hampir secepat. Saya akan menggunakan metode Anda.
Mahakuasa

Tetapi, melompat ke memset adalah instruksi tunggal, jadi menggunakannya akan menghasilkan ukuran biner yang lebih kecil.
Alexander Shishenko

2
ini bukan apa yang diminta OP, tetapi hanya menugaskan kembali vektor Anda ke yang baru dengan ukuran yang sama ( v = std::vector<int>(vec_size,0)) tampaknya sedikit lebih cepat daripada filldi komputer saya
Yibo Yang

1
Ini adalah cara paling idiomatis untuk melakukannya, lebih idiomatis daripada menggunakan assign.
alfC

1
apakah menugaskan ke vektor baru melakukan penumpukan alokasi? dan kemudian buang alokasi vektor yang ada? Saya bisa melihat bahwa menjadi lebih lambat daripada memset et al
Conrad Jones

150

Seperti biasa ketika Anda bertanya tentang tercepat: Ukur! Menggunakan Metode di atas (pada Mac menggunakan Dentang):

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    |

menggunakan 100000 iterasi pada vektor 10.000 int.

Edit: Jika changeing nomor ini masuk akal perubahan kali yang dihasilkan Anda dapat memiliki beberapa keyakinan (tidak sebagus memeriksa kode perakitan akhir) bahwa patokan buatan belum dioptimalkan pergi seluruhnya. Tentu saja yang terbaik adalah mengacaukan kinerja dalam kondisi nyata. end Edit

untuk referensi kode yang digunakan:

#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;
}

Kesimpulan: gunakan std::fill(karena, seperti orang lain katakan paling idiomatis)!


3
+1. Benchmark khusus ini tidak konklusif, tetapi intinya benar-benar benar, Anda harus menulis tes kinerja alternatif karena mereka benar-benar akan digunakan. Jika tidak ada perbedaan kinerja, gunakan sumber mana yang paling sederhana.
Steve Jessop

3
"... tidak konklusif ..." IMO ketidakkonsistenan ini dalam dirinya sendiri sudah merupakan poin yang baik untuk melakukan benchmark, lebih sering daripada tidak Pengoptimal sudah melakukan pekerjaan yang sangat baik untuk jenis situasi yang ditanyakan OP. Dan saya akan memodifikasi kalimat terakhir Anda untuk membaca "Jika tidak ada perbedaan kinerja yang signifikan ..."
Fabio Fracassi

4
UPDATE Menggunakan Nonius untuk tolok ukur: clang3.6-libc ++ - c ++ 1y-O3 , gcc4.9-c ++ 1y-O3 dan gcc5-c ++ 1y-O3 - TL; DR : assignlebih lambat, kecuali untuk kapasitas kecil pada libc++. CODE coliru / paste
lihat

2
Juga, wow, jika Anda peduli tentang kecepatan tanpa optimisasi (yang mungkin masuk akal jika Anda menggunakan mode 'debug', yang dilakukan beberapa tim), fillterlihat mengerikan. Ini dua urutan besarnya lebih lambat dalam tes ini.
Kyle Strand

5
@KyleStrand: Bukan isinya mengerikan, tapi templat dan kode dihasilkan dengan -O0 di dalam unit terjemahan Anda. Saat Anda menggunakan memset, Anda menggunakan kode libc yang dikompilasi dengan -O3 (bahkan ketika Anda mengkompilasi kode Anda dengan -O0). Jika Anda peduli tentang kecepatan dalam debug dan Anda menggunakan templat, Anda harus menggunakan instantiasi templat eksplisit dalam file terpisah yang Anda kompilasi dengan -O3
Tic

25

Bagaimana dengan assignfungsi anggota?

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

2
OP ingin mengatur ulang nilai yang ada, tetapi jawaban Anda lebih baik ketika ingin mengubah ukuran dan mengatur ulang nilai. Terima kasih!

15

Jika itu hanya vektor bilangan bulat, pertama-tama saya akan mencoba:

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

Ini tidak terlalu C ++, jadi saya yakin seseorang akan memberikan cara yang tepat untuk melakukan ini. :)


3
Karena standar (2003 TC1) menjamin bahwa std :: vector bersebelahan dalam memori, ini harus baik-baik saja. Jika pustaka c ++ Anda tidak sesuai dengan TC1 2003, maka jangan gunakan ini.
Mario

2
@ Mario: Saya tidak akan memposting ini kecuali itu benar dan diasumsikan terkenal, tentu saja. :) Tapi terima kasih.
bersantai

1
Saya memeriksa perakitan. The ::std::fillMetode memperluas untuk sesuatu yang cukup terkutuk cepat, meskipun sedikit di sisi kode-bloaty karena itu semua inline. Saya masih menggunakannya karena itu jauh lebih baik untuk dibaca.
Mahakuasa

4
Anda sebaiknya menambahkan memeriksa apakah vektor kosong dan tidak melakukan apa pun dalam kasus ini. Menghitung & membeli [0] untuk vektor kosong dapat menghasilkan pernyataan dalam kode STL.
Sergey

4

mencoba

std::fill

dan juga

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

ukurannya sangat bagus
Nick

3

Saya memiliki pertanyaan yang sama tetapi tentang yang agak pendek vector<bool>(afaik standar memungkinkan untuk mengimplementasikannya secara internal berbeda dari sekedar array elemen boolean yang berkelanjutan). Karena itu saya mengulangi tes yang sedikit dimodifikasi oleh Fabio Fracassi. Hasilnya adalah sebagai berikut (waktu, dalam detik):

            -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

Jadi ternyata untuk ukuran ini, vector<bool>::assign()lebih cepat. Kode yang digunakan untuk tes:

#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;
}

Saya menggunakan kompiler GCC 7.2.0 di Ubuntu 17.10. Baris perintah untuk kompilasi:

g++ -std=c++11 -O0 main.cpp
g++ -std=c++11 -O3 main.cpp
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.