std :: vector versus std :: array di C ++

283

Apa perbedaan antara a std::vectordan a std::arraydi C ++? Kapan sebaiknya satu lebih disukai daripada yang lain? Apa pro dan kontra dari masing-masing? Semua buku teks saya lakukan adalah daftar bagaimana mereka sama.

Zud
sumber
1
Saya mencari perbandingan std::vectorvs std::arraydan bagaimana istilahnya berbeda.
Zud
Zud, std::arraytidak sama dengan array C ++. std::arrayadalah pembungkus yang sangat tipis di sekitar array C ++, dengan tujuan utama menyembunyikan pointer dari pengguna kelas. Saya akan memperbarui jawaban saya.
ClosureCowboy
Saya memperbarui judul pertanyaan dan teks untuk mencerminkan klarifikasi Anda.
Matteo Italia

Jawaban:

318

std::vectoradalah kelas template yang merangkum array dinamis 1 , disimpan di heap, yang tumbuh dan menyusut secara otomatis jika elemen ditambahkan atau dihapus. Ini menyediakan semua kait ( begin(),, end()iterator, dll) yang membuatnya berfungsi dengan baik dengan sisa STL. Ini juga memiliki beberapa metode berguna yang memungkinkan Anda melakukan operasi yang pada array normal akan rumit, seperti misalnya memasukkan elemen di tengah-tengah vektor (ini menangani semua pekerjaan memindahkan elemen berikut di belakang layar).

Karena ia menyimpan elemen-elemen dalam memori yang dialokasikan pada heap, ia memiliki beberapa overhead sehubungan dengan array statis.

std::arrayadalah kelas templat yang merangkum array berukuran statis, disimpan di dalam objek itu sendiri, yang berarti bahwa, jika Anda instantiate kelas pada stack, array itu sendiri akan berada di stack. Ukurannya harus diketahui pada waktu kompilasi (dilewatkan sebagai parameter templat), dan tidak dapat tumbuh atau menyusut.

Ini lebih terbatas daripada std::vector, tetapi seringkali lebih efisien, terutama untuk ukuran kecil, karena dalam praktiknya sebagian besar pembungkus ringan di sekitar array gaya-C. Namun, ini lebih aman, karena konversi implisit ke penunjuk dinonaktifkan, dan menyediakan banyak fungsi terkait STL std::vectordan wadah lainnya, sehingga Anda dapat menggunakannya dengan mudah dengan algoritma & co STL. Bagaimanapun, untuk batasan ukuran tetap itu jauh lebih fleksibel daripada std::vector.

Untuk pengantar std::array, lihat artikel ini ; untuk pengantar cepat ke std::vectordan untuk operasi yang memungkinkan, Anda mungkin ingin melihat dokumentasinya .


  1. Sebenarnya, saya berpikir bahwa dalam standar mereka dijelaskan dalam hal kompleksitas maksimum dari operasi yang berbeda (misalnya akses acak dalam waktu konstan, iterasi atas semua elemen dalam waktu linier, penambahan dan penghapusan elemen pada akhirnya dalam waktu diamortisasi konstan, dll), tetapi AFAIK tidak ada metode lain untuk memenuhi persyaratan tersebut selain menggunakan array dinamis. Seperti yang dinyatakan oleh @Lucretiel, standar sebenarnya mengharuskan elemen disimpan secara bersebelahan, jadi itu adalah array dinamis, disimpan di mana pengalokasi terkait meletakkannya.
Matteo Italia
sumber
6
Mengenai catatan kaki Anda: Meskipun benar, standar ini juga menjamin bahwa aritmatika penunjuk pada elemen internal berfungsi, yang artinya harus berupa array: & vec [9] - & vec [3] == 6 benar.
Lucretiel
9
Saya cukup yakin, vektor itu tidak menyusut secara otomatis, tetapi karena C ++ 11 Anda dapat memanggil shrink_to_fit.
Dino
Saya benar-benar bingung dengan istilah array statis dan saya tidak yakin apa terminologi yang tepat. Maksud Anda array ukuran statis dan bukan array variabel statis (yang menggunakan penyimpanan statis). stackoverflow.com/questions/2672085/… . Apa terminologi yang benar? Apakah array statis adalah istilah ceroboh untuk array dengan ukuran tetap?
Z boson
3
@Zboson: jelas bukan hanya Anda, statis adalah istilah yang cukup disalahgunakan; sangat statickata kunci di C ++ memiliki tiga arti yang tidak terkait yang berbeda, dan istilah ini juga sering digunakan untuk berbicara tentang hal-hal yang tetap pada waktu kompilasi. Saya berharap bahwa "ukuran statis" sedikit lebih jelas.
Matteo Italia
3
Satu hal yang perlu catatan: Untuk real-time pemrograman (di mana Anda tidak seharusnya memiliki setiap alokasi dinamis / dealokasi setelah startup) std :: array mungkin akan lebih disukai daripada std :: vector.
TED
17

Menggunakan std::vector<T>kelas:

  • ... sama cepatnya dengan menggunakan array bawaan, dengan asumsi Anda hanya melakukan hal-hal yang dapat dilakukan oleh array bawaan (baca dan tulis ke elemen yang ada).

  • ... secara otomatis mengubah ukuran ketika elemen baru dimasukkan.

  • ... memungkinkan Anda untuk memasukkan elemen baru di awal atau di tengah vektor, secara otomatis "menggeser" elemen lainnya "ke atas" (apakah itu masuk akal?). Hal ini memungkinkan Anda untuk menghapus elemen di mana saja di std::vector, juga, secara otomatis menggeser sisa elemen ke bawah.

  • ... memungkinkan Anda untuk melakukan membaca rentang-diperiksa dengan at()metode (Anda selalu dapat menggunakan pengindeks []jika Anda tidak ingin pemeriksaan ini dilakukan).

Ada dua tiga peringatan utama untuk digunakan std::vector<T>:

  1. Anda tidak memiliki akses yang dapat diandalkan ke pointer yang mendasarinya, yang mungkin menjadi masalah jika Anda berurusan dengan fungsi pihak ketiga yang menuntut alamat array.

  2. The std::vector<bool>kelas konyol. Ini diimplementasikan sebagai bitfield yang terkondensasi, bukan sebagai array. Hindari jika Anda menginginkan array bools!

  3. Selama penggunaan, std::vector<T>s akan menjadi sedikit lebih besar dari array C ++ dengan jumlah elemen yang sama. Ini karena mereka perlu melacak sejumlah kecil informasi lain, seperti ukuran mereka saat ini, dan karena setiap kali std::vector<T>diubah ukurannya, mereka menyimpan lebih banyak ruang daripada yang mereka butuhkan. Ini untuk mencegah mereka harus mengubah ukuran setiap kali elemen baru dimasukkan. Perilaku ini dapat diubah dengan memberikan kebiasaan allocator, tetapi saya tidak pernah merasa perlu melakukan itu!


Sunting: Setelah membaca balasan Zud untuk pertanyaan itu, saya merasa saya harus menambahkan ini:

The std::array<T>kelas tidak sama dengan C ++ array yang. std::array<T>adalah pembungkus yang sangat tipis di sekitar array C ++, dengan tujuan utama menyembunyikan pointer dari pengguna kelas (dalam C ++, array secara implisit dilemparkan sebagai pointer, seringkali untuk efek yang mengecewakan). The std::array<T>kelas juga menyimpan ukuran (panjang), yang bisa sangat berguna.

ClosureCowboy
sumber
5
Ini 'sama cepatnya' dengan menggunakan array bawaan yang dialokasikan secara dinamis. Di sisi lain, menggunakan array otomatis mungkin memiliki kinerja yang sangat berbeda (dan tidak hanya selama alokasi, karena efek lokalitas).
Ben Voigt
4
Untuk vektor non-bool di C ++ 11 dan yang lebih baru, Anda dapat memanggil data()a std::vector<T>untuk mendapatkan pointer yang mendasarinya. Anda juga dapat mengambil alamat elemen 0 (dijamin untuk bekerja dengan C ++ 11, mungkin akan bekerja dengan versi sebelumnya).
Matt
16

Untuk menekankan poin yang dibuat oleh @MatteoItalia, perbedaan efisiensi adalah di mana data disimpan. Memori tumpukan (diperlukan dengan vector) memerlukan panggilan ke sistem untuk mengalokasikan memori dan ini bisa mahal jika Anda menghitung siklus. Stack memory (mungkin untuk array) secara virtual "zero-overhead" dalam hal waktu, karena memori dialokasikan dengan hanya menyesuaikan stack pointer dan dilakukan hanya sekali saat masuk ke suatu fungsi. Tumpukan juga menghindari fragmentasi memori. Yang pasti, std::arraytidak akan selalu ada di tumpukan; itu tergantung di mana Anda mengalokasikannya, tetapi itu masih akan melibatkan alokasi memori kurang dari tumpukan dibandingkan dengan vektor. Jika Anda punya

  • "array" kecil (di bawah 100 elemen katakan) - (tumpukan khas sekitar 8MB, jadi jangan mengalokasikan lebih dari beberapa KB pada tumpukan atau kurang jika kode Anda bersifat rekursif)
  • ukuran akan diperbaiki
  • masa pakai berada dalam lingkup fungsi (atau nilai anggota dengan masa hidup yang sama dengan kelas induk)
  • Anda menghitung siklus,

pasti menggunakan std::arraylebih dari satu vektor. Jika salah satu dari persyaratan itu tidak benar, maka gunakan a std::vector.

Mark Lakata
sumber
3
Jawaban bagus. "Yang pasti, std :: array tidak akan selalu berada di stack; itu tergantung pada di mana Anda mengalokasikannya" Jadi bagaimana saya bisa membuat std :: array tidak di stack dengan sejumlah elemen?
Trilarion
4
@Trilarion menggunakan new std::arrayatau menjadikannya anggota kelas yang Anda gunakan 'baru' untuk mengalokasikan.
Mark Lakata
Jadi ini berarti new std::arraymasih berharap untuk mengetahui ukurannya pada waktu kompilasi dan tidak dapat mengubah ukurannya tetapi masih hidup di tumpukan?
Trilarion
Iya. Tidak ada keuntungan yang signifikan untuk menggunakan new std::arrayvs new std::vector.
Mark Lakata
12

Jika Anda mempertimbangkan untuk menggunakan array multidimensi, maka ada satu perbedaan tambahan antara std :: array dan std :: vector. Array multidimensi std :: akan memiliki elemen yang dikemas dalam memori di semua dimensi, seperti halnya array gaya ac. Std :: vektor multidimensi tidak akan dikemas dalam semua dimensi.

Diberikan deklarasi berikut:

int cConc[3][5];
std::array<std::array<int, 5>, 3> aConc;
int **ptrConc;      // initialized to [3][5] via new and destructed via delete
std::vector<std::vector<int>> vConc;    // initialized to [3][5]

Pointer ke elemen pertama dalam array c-style (cConc) atau std :: array (aConc) dapat diulang melalui seluruh array dengan menambahkan 1 ke setiap elemen sebelumnya. Mereka penuh sesak.

Pointer ke elemen pertama dalam array vektor (vConc) atau array pointer (ptrConc) hanya dapat diulang melalui elemen 5 (dalam hal ini) pertama, dan kemudian ada 12 byte (pada sistem saya) dari overhead untuk vektor berikutnya.

Ini berarti bahwa array std :: vector> yang diinisialisasi sebagai array [3] [1000] akan jauh lebih kecil dalam memori daripada array yang diinisialisasi sebagai array [1000] [3], dan keduanya akan lebih besar dalam memori daripada std: array dialokasikan dengan cara baik.

Ini juga berarti bahwa Anda tidak dapat dengan mudah mengirimkan array vektor (atau penunjuk) multidimensi ke, katakanlah, openGL tanpa memperhitungkan overhead memori, tetapi Anda dapat secara naif meneruskan array std :: array multidimensi ke openGL dan menjalankannya.

psimpson
sumber
-17

Vektor adalah kelas wadah sementara array adalah memori yang dialokasikan.

Saif al Harthi
sumber
23
Jawaban Anda tampaknya ditujukan std::vector<T>versus T[], tetapi pertanyaannya adalah tentang std::vector<T>versus std::array<T>.
Keith Pinson