Haruskah array digunakan dalam C ++?

96

Sejak std::listdan std::vectorada, apakah ada alasan untuk menggunakan array C tradisional di C ++, atau haruskah mereka dihindari, sama seperti malloc?

Andreas
sumber
18
@Als: Pertanyaan itu menyangkut perbedaan antara dua container tertentu, sedangkan pertanyaan ini menyangkut perbedaan antara array mentah dan container standar secara umum.
Jon Purdy

Jawaban:

109

Dalam C ++ 11 mana std::arraytersedia, jawabannya adalah "ya, array harus dihindari". Sebelum C ++ 11, Anda mungkin perlu menggunakan larik C untuk mengalokasikan larik dalam penyimpanan otomatis (yaitu di tumpukan).

dasblinkenlight
sumber
3
Namun, banyak kompiler yang masih kekurangan dukungan C ++ 11. Anda harus memutuskan kapan lebih baik menggunakan satu daripada yang lain karena kurangnya std :: array
Nowayz
4
std :: array adalah template, yang memengaruhi proyek besar dalam hal waktu pembuatan dan kemungkinan ukuran kode karena untuk setiap kombinasi T, N template dibuat lagi.
zvrba
std :: vector menjamin penyelarasan data dengan standar, sehingga dapat digunakan hampir di semua tempat. Dengan C ++ 11 sebenarnya tidak ada alasan untuk menggunakan array C.
Nils
16
Array @Nils juga menjamin keselarasan. Plus, alokasi penyimpanan otomatis ("tumpukan") jauh lebih cepat daripada alokasi penyimpanan dinamis. Jika saya tahu saya memiliki tepat 3 elemen [misalnya, koordinat segitiga], tidak ada alasan untuk menggunakan vektor.
zvrba
9
@zvrba - Periksa rakitan yang dihasilkan saat menggunakan larik std :: array vs C. Tidak ada perbedaan sama sekali.
Nemanja Trifunovic
85

Jelas, meskipun dengan std::arrayC ++ 11, praktis hanya untuk data statis. Array gaya C memiliki tiga keunggulan penting dibandingkan std::vector:

  • Mereka tidak membutuhkan alokasi dinamis. Untuk alasan ini, array gaya C lebih disukai di mana Anda cenderung memiliki banyak array yang sangat kecil. Katakan sesuatu seperti titik n-dimensi:

    template <typename T, int dims>
    class Point
    {
        T myData[dims];
    // ...
    };

    Biasanya, orang mungkin membayangkan yang dimsakan sangat kecil (2 atau 3), Ttipe built-in ( double), dan Anda mungkin berakhir std::vector<Point>dengan jutaan elemen. Anda pasti tidak ingin jutaan alokasi dinamis 3 dobel.

  • Dukungan inisialisasi statis. Ini hanya masalah untuk data statis, di mana sesuatu seperti:

    struct Data { int i; char const* s; };
    Data const ourData[] =
    {
        { 1, "one" },
        { 2, "two" },
        //  ...
    };

    Ini sering lebih disukai daripada menggunakan vektor (dan std::string), karena ini menghindari semua urutan masalah inisialisasi; data dimuat sebelumnya, sebelum kode aktual apa pun dapat dieksekusi.

  • Terakhir, terkait dengan hal di atas, compiler dapat menghitung ukuran sebenarnya dari array dari penginisialisasi. Anda tidak harus menghitungnya.

Jika Anda memiliki akses ke C ++ 11, std::arraypecahkan dua masalah pertama, dan sebaiknya digunakan dalam preferensi larik gaya C dalam kasus pertama. Namun, ini tidak membahas yang ketiga, dan memiliki dimensi kompiler array yang sesuai dengan jumlah penginisialisasi masih merupakan alasan yang valid untuk memilih array gaya C.

James Kanze
sumber
11
Inisialisasi array gaya-C juga menghilangkan kebutuhan untuk mengulang sendiri. int i[] = { 1, 2, 3 };terus bekerja dengan int i[] = { 1, 2, 3, 4 };. array<int, 3>perlu diubah secara manual menjadi array<int, 4>.
10
@JoeWreschnig Perubahan yang mudah Anda lupakan. Jika Anda menambahkan sebuah elemen, kompilator akan mengeluh, tetapi jika Anda menghapusnya, Anda akan mendapatkan tambahan, elemen yang diinisialisasi 0 di akhir. Saya masih menggunakan array gaya C secara ekstensif untuk data statis semacam ini.
James Kanze
3
Kalimat pertama tidak masuk akal.
Konrad Rudolph
4
Poin ketiga dapat diselesaikan dengan cukup elegan dengan menggunakan make_arrayfungsi , mirip dengan make_pairdll. Hat-tip to @R. Martinho Fernandes .
Konrad Rudolph
@KonradRolol: Tentu saja. Andreas bertanya "Haruskah array digunakan dalam C ++?", Yang dijawab James "Pasti, meskipun dengan std::arraydi C ++ 11, [mereka harus digunakan] praktis hanya untuk data statis".
Jon Purdy
15

Jangan pernah mengatakan "tidak pernah", tetapi saya setuju bahwa peran mereka sangat berkurang oleh struktur data yang sebenarnya dari STL.

Saya juga akan mengatakan bahwa enkapsulasi di dalam objek harus meminimalkan dampak pilihan seperti ini. Jika array adalah anggota data pribadi, Anda dapat menukarnya masuk atau keluar tanpa memengaruhi klien kelas Anda.

duffymo
sumber
11

Saya telah mengerjakan sistem keamanan kritis di mana Anda tidak dapat menggunakan alokasi memori dinamis. Memori harus selalu ada di tumpukan. Oleh karena itu dalam kasus ini Anda akan menggunakan array karena ukurannya ditetapkan pada waktu kompilasi.

Ed Heal
sumber
8
Sebelum C ++ 11 saya akan setuju, tetapi std::array<T>mengalokasikan pada tumpukan dan pada dasarnya tidak memiliki overhead pada array mentah.
111111
5
@ 111111 - Setuju. Tapi saya tahu beberapa orang di industri itu belum pindah ke C ++ 11
Ed Heal
Saya tahu itulah mengapa saya tidak meremehkan Anda, tetapi saya pikir boost memiliki versi dan mudah untuk menggulirnya sendiri juga.
111111
6
tetapi dalam sistem keamanan kritis, Anda tidak menggunakan fitur kompiler baru (kurang teruji), dan Anda tidak menggunakan boost.
James Kanze
3
Banyak sistem penting keamanan dibangun di atas kompiler LAMA yang bahkan tidak memiliki fitur kompilator yang lebih baru karena mengubah toolchain adalah proses yang lambat dan mahal yang membutuhkan banyak dokumen, pengujian, dan sertifikasi.
Brian McFarland
6

arraydi c++memberi Anda alternatif ukuran tetap cepat dari ukuran dinamis std::vectordan std::list. std :: array adalah salah satu penambahan pada c++11. Ini memberikan manfaat dari kontainer std sambil tetap menyediakan semantik tipe agregat dari array gaya C.

Jadi c++11saya pasti akan menggunakan std::array, di mana diperlukan, lebih dari vektor. Tapi saya akan menghindari array gaya C di C++03.

Vikas
sumber
4

Biasanya, tidak , saya tidak bisa memikirkan alasan untuk menggunakan array mentah, katakanlah vectors,. Jika kodenya baru .

Anda mungkin harus menggunakan array jika perpustakaan Anda harus kompatibel dengan kode yang mengharapkan array dan pointer mentah.

Luchian Grigore
sumber
1
... tetapi karena C ++ 03 vektor "sebenarnya memiliki" larik, yang dapat Anda akses dengan penunjuk untuk membaca atau menulis. Jadi itu mencakup sebagian besar kasus kode yang mengharapkan pointer ke array. Hanya benar-benar ketika kode itu mengalokasikan atau membebaskan array Anda tidak dapat menggunakan vektor.
Steve Jessop
@ StevenJessop Bisakah Anda mengakses array internal?
Luchian Grigore
1
@LuchianGrigore: vector.data()di C ++ 11 atau &vector.front()sebelumnya.
Mike Seymour
@Luchian: asalkan vektor tidak kosong, Anda dapat mengarahkan pointer ke elemen (dan jika kosong, Anda dapat meneruskan pointer null dan panjang 0 ke fungsi apa pun yang ditulis dengan baik yang menerima kapitalisasi edge a buffer berukuran nol). Cukup banyak satu-satunya tujuan dari jaminan kedekatan vektor yang ditambahkan dalam C ++ 03 adalah untuk memungkinkan vektor digunakan sebagai buffer oleh kode berorientasi pointer.
Steve Jessop
1
@SteveJessop Dan fakta bahwa banyak orang mengira itu dijamin, dan dianggap lebih baik untuk tidak mengecewakan mereka.
James Kanze
4

Saya tahu banyak orang menunjukkan std :: array untuk mengalokasikan array pada stack, dan std :: vector untuk heap. Tapi tampaknya tidak ada yang mendukung keselarasan non-pribumi. Jika Anda melakukan kode numerik apa pun yang Anda ingin gunakan instruksi SSE atau VPX (sehingga membutuhkan penyejajaran 128 atau 256 byte masing-masing), array C tampaknya masih menjadi pilihan terbaik Anda.

gct
sumber
3

Saya akan mengatakan array masih berguna, jika Anda menyimpan sejumlah kecil data statis, mengapa tidak.

james82345
sumber
2

Satu-satunya keuntungan dari sebuah array (tentu saja dibungkus dalam sesuatu yang akan mengelola deallokasi secara otomatis saat dibutuhkan) yang std::vectordapat saya pikirkan adalah bahwa vectortidak dapat melewatkan kepemilikan datanya, kecuali kompiler Anda mendukung C ++ 11 dan memindahkan konstruktor.

Tadeusz Kopec
sumber
6
"vektor tidak bisa melewatkan kepemilikan datanya" - ya bisa, di C ++ 03, menggunakan swap.
Steve Jessop
2

Array gaya C adalah struktur data fundamental, jadi akan ada kasus ketika lebih baik menggunakannya. Namun, untuk kasus umum, gunakan struktur data yang lebih canggih yang membulatkan sudut data yang mendasarinya. C ++ memungkinkan Anda melakukan beberapa hal yang sangat menarik dan berguna dengan memori, banyak di antaranya bekerja dengan array sederhana.

James Wynn
sumber
3
Bagaimana array C-style lebih fundamental daripada std::arrays? Keduanya dalam banyak kasus akan dikompilasi ke perakitan yang sama.
kiri sekitar
1
Lebih mendasar dalam hal itu lebih mendasar. Anda tahu apa yang akan dilakukan sebuah array, std :: array mungkin memiliki penerapan quirks karena bergantung pada pustaka standar.
James Wynn
1
@JamesWynn Tidak juga. std::arraymemiliki semantik yang didefinisikan secara tepat yang dibangun di atas array statis.
Konrad Rudolph
1

Anda harus menggunakan kontainer STL secara internal, tetapi Anda tidak boleh meneruskan pointer ke kontainer tersebut di antara modul yang berbeda, atau Anda akan berakhir di neraka ketergantungan. Contoh:

std::string foo;
//  fill foo with stuff
myExternalOutputProc(foo.c_str());

adalah solusi yang sangat bagus tetapi tidak

std::string foo;
//  fill foo with stuff
myExternalOutputProc(&foo);

Alasannya adalah bahwa std :: string dapat diimplementasikan dengan banyak cara berbeda tetapi string gaya-c selalu merupakan string gaya-c.

pengguna877329
sumber
Saya pikir apa yang ingin Anda katakan adalah: Jangan menghubungkan kode objek yang berbeda bersama-sama jika kompiler / implementasi yang berbeda dari perpustakaan standar digunakan untuk membuatnya. Itu memang benar. Bagaimana ini berhubungan dengan pertanyaan awal?
jogojapan
Ini hanyalah sebuah saran ketika menggunakan array atau kontainer STL. Buat data menggunakan container, teruskan sebagai array. Untuk data lain yang membuat string Anda akan memiliki sesuatu seperti myExternalOutputProc (foo.rawPointerGet (), foo.count ());
user877329
Tetapi masalah ini hanya muncul ketika Anda menggabungkan implementasi yang berbeda dari pustaka standar dalam proyek yang sama. Itu gila. Dalam kode normal mana pun, tidak masalah untuk meneruskan, katakanlah, vektor, dengan referensi (atau, dalam C ++ 11, pindahkan) ke suatu fungsi.
jogojapan
1
Saya kebetulan menyukai plugin
user877329