Dalam kursus C ++ kami, mereka menyarankan untuk tidak menggunakan array C ++ pada proyek baru lagi. Sejauh yang saya tahu Stroustroup sendiri menyarankan untuk tidak menggunakan array. Tetapi apakah ada perbedaan kinerja yang signifikan?
208
int main(int argc, const std::vector<string>& argv)
Jawaban:
Menggunakan array C ++ dengan
new
(yaitu, menggunakan array dinamis) harus dihindari. Ada masalah Anda harus melacak ukurannya, dan Anda harus menghapusnya secara manual dan melakukan semua jenis pembersihan.Menggunakan array pada stack juga tidak disarankan karena Anda tidak memiliki pemeriksaan jangkauan, dan melewatkan array akan kehilangan informasi tentang ukurannya (konversi array ke pointer). Anda harus menggunakan
boost::array
dalam kasus itu, yang membungkus array C ++ di kelas kecil dan menyediakansize
fungsi dan iterator untuk beralih di atasnya.Sekarang array std :: vector vs asli C ++ (diambil dari internet):
Catatan: Jika Anda mengalokasikan array dengan
new
dan mengalokasikan objek non-kelas (seperti polosint
) atau kelas tanpa konstruktor yang ditentukan pengguna dan Anda tidak ingin elemen Anda diinisialisasi pada awalnya, menggunakannew
array yang dialokasikan dapat memiliki keunggulan kinerja karenastd::vector
menginisialisasi semua elemen ke nilai default (0 untuk int, misalnya) pada konstruksi (kredit ke @bernie untuk mengingatkan saya).sumber
Pembukaan untuk orang pengoptimal mikro
Ingat:
(Berkat metamorfosis untuk kutipan lengkapnya)
Jangan gunakan array C alih-alih vektor (atau apa pun) hanya karena Anda percaya itu lebih cepat karena seharusnya tingkat yang lebih rendah. Kamu akan salah
Gunakan dengan vektor default (atau wadah aman disesuaikan dengan kebutuhan Anda), dan kemudian jika profiler Anda mengatakan itu adalah masalah, lihat apakah Anda dapat mengoptimalkannya, baik dengan menggunakan algoritma yang lebih baik, atau mengubah wadah.
Ini mengatakan, kita bisa kembali ke pertanyaan semula.
Statis / Array Dinamis?
Kelas array C ++ berperilaku lebih baik daripada array C tingkat rendah karena mereka tahu banyak tentang diri mereka sendiri, dan dapat menjawab pertanyaan array C tidak bisa. Mereka mampu membersihkan diri mereka sendiri. Dan yang lebih penting, mereka biasanya ditulis menggunakan templat dan / atau inlining, yang berarti bahwa apa yang tampak pada banyak kode dalam debug memutuskan untuk sedikit atau tidak ada kode yang diproduksi dalam rilis rilis, yang berarti tidak ada perbedaan dengan persaingan bawaan yang kurang aman.
Secara keseluruhan, itu jatuh pada dua kategori:
Array dinamis
Menggunakan pointer ke malloc-ed / new-ed array akan lebih baik secepat versi std :: vector, dan jauh lebih tidak aman (lihat posting litb ).
Jadi gunakan std :: vector.
Array statis
Menggunakan array statis adalah yang terbaik:
Jadi gunakan std :: array .
Memori tidak diinisialisasi
Kadang-kadang, menggunakan
vector
alih - alih buffer mentah menimbulkan biaya yang terlihat karenavector
akan menginisialisasi buffer pada konstruksi, sedangkan kode yang diganti tidak, seperti dikatakan bernie dalam jawabannya .Jika ini masalahnya, maka Anda bisa menanganinya dengan menggunakan
unique_ptr
alih - alihvector
atau, jika kasing itu tidak luar biasa dalam codeline Anda, sebenarnya tulislah kelasbuffer_owner
yang akan memiliki memori itu, dan memberi Anda akses yang mudah dan aman ke sana, termasuk bonus seperti mengubah ukurannya (menggunakanrealloc
?), atau apa pun yang Anda butuhkan.sumber
Vektor adalah array di bawah kap. Kinerjanya sama.
Satu tempat di mana Anda dapat mengalami masalah kinerja, tidak mengukur vektor dengan benar untuk memulai.
Sebagai vektor mengisi, itu akan mengubah ukuran sendiri, dan itu bisa menyiratkan, alokasi array baru, diikuti oleh n copy constructor, diikuti oleh tentang n panggilan destructor, diikuti oleh penghapusan array.
Jika konstruk / destruksi Anda mahal, Anda jauh lebih baik membuat vektor ukuran yang benar untuk memulai.
Ada cara sederhana untuk menunjukkan ini. Buat kelas sederhana yang menunjukkan kapan dibangun / dihancurkan / disalin / ditugaskan. Buat vektor hal-hal ini, dan mulailah mendorongnya di bagian belakang vektor. Ketika vektor terisi, akan ada kaskade aktivitas saat ukuran vektor berubah. Kemudian coba lagi dengan ukuran vektor ke jumlah elemen yang diharapkan. Anda akan melihat perbedaannya.
sumber
std::vector
kedengarannya standar-tidak sesuai? Saya percaya standar mensyaratkan bahwavector::push_back
kompleksitas konstan diamortisasi, dan peningkatan kapasitas sebesar 1 pada masingpush_back
- masing akan menjadi kompleksitas n ^ 2 setelah Anda memperhitungkan reallocs. - menganggap semacam peningkatan kapasitas eksponensialpush_back
daninsert
, kegagalan untuk paling banyakreserve
akan menyebabkan peningkatan faktor konstan dalam salinan konten vektor. Faktor pertumbuhan vektor 1,5 eksponensial berarti ~ 3x lebih banyak salinan jika Anda gagalreserve()
.Untuk menanggapi sesuatu yang dikatakan Mehrdad :
Tidak benar sama sekali. Vektor terdegradasi dengan baik menjadi array / pointer jika Anda menggunakan:
Ini berfungsi untuk semua implementasi STL utama. Dalam standar berikutnya, itu akan diperlukan untuk bekerja (meskipun tidak apa-apa hari ini).
sumber
&v[n] == &v[0] + n
valid disediakann
dalam kisaran ukuran. Paragraf yang berisi pernyataan ini tidak berubah dengan C ++ 11.Anda memiliki lebih sedikit alasan untuk menggunakan larik biasa di C ++ 11.
Ada 3 jenis array di alam dari yang tercepat ke yang paling lambat, tergantung pada fitur yang mereka miliki (tentu saja kualitas implementasi dapat membuat segalanya sangat cepat bahkan untuk kasus 3 dalam daftar):
std::array<T, N>
dynarray
di C ++ TS setelah C ++ 14. Di C ada VLAstd::vector<T>
Untuk 1. array statis sederhana dengan jumlah elemen tetap, gunakan
std::array<T, N>
dalam C ++ 11.Untuk 2 array ukuran tetap yang ditentukan pada saat runtime, tetapi itu tidak akan mengubah ukurannya, ada diskusi di C ++ 14 tetapi telah dipindahkan ke spesifikasi teknis dan akhirnya dibuat dari C ++ 14.
Untuk 3.
std::vector<T>
biasanya akan meminta memori di heap . Ini dapat memiliki konsekuensi kinerja, meskipun Anda dapat menggunakannyastd::vector<T, MyAlloc<T>>
untuk memperbaiki situasi dengan pengalokasi khusus. Keuntungan dibandingkanT mytype[] = new MyType[n];
adalah bahwa Anda dapat mengubah ukurannya dan itu tidak akan membusuk ke pointer, seperti array biasa.Gunakan tipe pustaka standar yang disebutkan untuk menghindari array yang membusuk ke pointer . Anda akan menghemat waktu debug dan kinerjanya persis sama dengan array biasa jika Anda menggunakan set fitur yang sama.
sumber
Pergilah dengan STL. Tidak ada penalti kinerja. Algoritma sangat efisien dan mereka melakukan pekerjaan yang baik dalam menangani jenis detail yang sebagian besar dari kita tidak akan pikirkan.
sumber
STL adalah perpustakaan yang sangat dioptimalkan. Bahkan, disarankan untuk menggunakan STL dalam game di mana kinerja tinggi mungkin diperlukan. Array terlalu rawan kesalahan untuk digunakan dalam tugas sehari-hari. Kompiler hari ini juga sangat cerdas dan benar-benar dapat menghasilkan kode yang sangat baik dengan STL. Jika Anda tahu apa yang Anda lakukan, STL biasanya dapat memberikan kinerja yang diperlukan. Misalnya dengan menginisialisasi vektor ke ukuran yang diperlukan (jika Anda tahu dari awal), Anda pada dasarnya dapat mencapai kinerja array. Namun, mungkin ada kasus di mana Anda masih membutuhkan array. Saat berinteraksi dengan kode tingkat rendah (mis. Perakitan) atau pustaka lama yang membutuhkan array, Anda mungkin tidak dapat menggunakan vektor.
sumber
vec.data()
untuk data danvec.size()
ukuran. Sangat mudah.Tentang kontribusi duli .
Kesimpulannya adalah bahwa array bilangan bulat lebih cepat daripada vektor bilangan bulat (5 kali dalam contoh saya). Namun, array dan vektor diselubungi dengan kecepatan yang sama untuk data yang lebih kompleks / tidak selaras.
sumber
Jika Anda mengkompilasi perangkat lunak dalam mode debug, banyak kompiler tidak akan inline fungsi pengaksesor vektor. Ini akan membuat implementasi vektor stl jauh lebih lambat dalam situasi di mana kinerja merupakan masalah. Ini juga akan membuat kode lebih mudah di-debug karena Anda dapat melihat di debugger berapa banyak memori yang dialokasikan.
Dalam mode yang dioptimalkan, saya berharap vektor stl untuk mendekati efisiensi array. Ini karena banyak metode vektor sekarang digarisbawahi.
sumber
Pasti ada dampak kinerja untuk menggunakan
std::vector
vs array mentah ketika Anda ingin buffer tidak diinisialisasi (misalnya untuk digunakan sebagai tujuanmemcpy()
). Sebuahstd::vector
akan menginisialisasi semua elemennya menggunakan konstruktor default. Array mentah tidak akan.Spesifikasi c ++ untuk
std:vector
konstruktor yang mengambilcount
argumen (ini bentuk ketiga) menyatakan:Array mentah tidak dikenakan biaya inisialisasi ini.
Lihat juga Bagaimana saya bisa menghindari std :: vector <> untuk menginisialisasi semua elemennya?
sumber
Perbedaan kinerja antara keduanya sangat tergantung pada implementasi - jika Anda membandingkan std :: vector yang diimplementasikan dengan buruk dengan implementasi array yang optimal, array akan menang, tetapi balikkan dan vektor akan menang ...
Selama Anda membandingkan apel dengan apel (baik array dan vektor memiliki jumlah elemen tetap, atau keduanya diubah ukurannya secara dinamis), saya akan berpikir bahwa perbedaan kinerja dapat diabaikan selama Anda mengikuti praktik pengkodean STL. Jangan lupa bahwa menggunakan kontainer C ++ standar juga memungkinkan Anda memanfaatkan algoritme pra-linting yang merupakan bagian dari pustaka C ++ standar dan kebanyakan dari mereka cenderung berkinerja lebih baik daripada implementasi rata-rata dari algoritma yang sama yang Anda buat sendiri. .
Yang mengatakan, IMHO vektor menang dalam skenario debug dengan debug STL karena kebanyakan implementasi STL dengan mode debug yang tepat setidaknya dapat menyoroti / menghapus kesalahan khas yang dibuat oleh orang-orang ketika bekerja dengan wadah standar.
Oh, dan jangan lupa bahwa array dan vektor berbagi tata letak memori yang sama sehingga Anda dapat menggunakan vektor untuk meneruskan data ke kode C atau C ++ lama yang mengharapkan array dasar. Perlu diingat bahwa sebagian besar taruhan tidak aktif dalam skenario itu, dan Anda berurusan dengan memori mentah lagi.
sumber
std::deque
bisa digunakan.Jika Anda tidak perlu menyesuaikan ukuran secara dinamis, Anda memiliki overhead memori untuk menghemat kapasitas (satu penunjuk / size_t). Itu dia.
sumber
Mungkin ada beberapa tepi kasus di mana Anda memiliki akses vektor di dalam fungsi inline di dalam fungsi inline, di mana Anda telah melampaui apa yang kompiler akan sebaris dan itu akan memaksa pemanggilan fungsi. Itu akan sangat jarang untuk tidak perlu dikhawatirkan - secara umum saya akan setuju dengan litb .
Saya terkejut belum ada yang menyebutkan ini - jangan khawatir tentang kinerja sampai terbukti menjadi masalah, lalu tolok ukur.
sumber
Saya berpendapat bahwa perhatian utama bukanlah kinerja, tetapi keamanan. Anda dapat membuat banyak kesalahan dengan array (pertimbangkan untuk mengubah ukuran, misalnya), di mana vektor akan menghemat banyak rasa sakit.
sumber
Vektor menggunakan sedikit lebih banyak memori daripada array karena mengandung ukuran array. Mereka juga meningkatkan ukuran hard disk program dan mungkin jejak memori program. Peningkatan ini kecil, tetapi mungkin penting jika Anda bekerja dengan sistem tertanam. Meskipun sebagian besar tempat di mana perbedaan ini penting adalah tempat di mana Anda akan menggunakan C daripada C ++.
sumber
Tes sederhana berikut:
C ++ Array vs Vektor penjelasan tes kinerja
bertentangan dengan kesimpulan dari "Perbandingan kode assembly yang dihasilkan untuk pengindeksan dasar, dereferencing, dan operasi kenaikan pada vektor dan array / pointer."
Harus ada perbedaan antara array dan vektor. Tes mengatakan begitu ... coba saja, kodenya ada ...
sumber
Terkadang array memang lebih baik daripada vektor. Jika Anda selalu memanipulasi set objek dengan panjang tetap, array lebih baik. Pertimbangkan cuplikan kode berikut:
di mana versi vektor X adalah
dan versi array X adalah:
Versi array akan main () akan lebih cepat karena kita menghindari overhead "baru" setiap kali di loop dalam.
(Kode ini telah diposting ke comp.lang.c ++ oleh saya).
sumber
Jika Anda menggunakan vektor untuk mewakili perilaku multidimensi, ada hit kinerja.
Apakah vektor 2d + menyebabkan hit kinerja?
Intinya adalah bahwa ada sejumlah kecil overhead dengan masing-masing sub-vektor memiliki informasi ukuran, dan tidak harus ada serialisasi data (seperti ada dengan array c multi-dimensi). Kurangnya serialisasi ini dapat menawarkan peluang optimasi yang lebih besar daripada mikro. Jika Anda melakukan array multi-dimensi, mungkin yang terbaik adalah hanya memperpanjang std :: vector dan gulung fungsi bit get / set / resize Anda sendiri.
sumber
Dengan asumsi array panjang tetap (misalnya
int* v = new int[1000];
vsstd::vector<int> v(1000);
, dengan ukuranv
tetap tetap pada 1000), satu-satunya pertimbangan kinerja yang benar-benar penting (atau setidaknya penting bagi saya ketika saya berada dalam dilema yang sama) adalah kecepatan akses ke elemen. Saya mencari kode vektor STL, dan inilah yang saya temukan:Fungsi ini pasti akan digarisbawahi oleh kompiler. Jadi, selama satu-satunya hal yang Anda rencanakan
v
adalah mengakses elemen-elemennyaoperator[]
, sepertinya tidak ada perbedaan kinerja yang sesungguhnya.sumber