Apakah elemen std :: vector dijamin bersebelahan?

111

Pertanyaan saya sederhana: apakah elemen std :: vector dijamin bersebelahan? Dalam urutan kata, dapatkah saya menggunakan penunjuk ke elemen pertama dari std :: vector sebagai C-array?

Jika ingatan saya bermanfaat bagi saya, standar C ++ tidak membuat jaminan seperti itu. Namun, persyaratan std :: vector sedemikian rupa sehingga hampir tidak mungkin untuk memenuhinya jika elemen tidak bersebelahan.

Adakah yang bisa menjelaskan ini?

Contoh:

std::vector<int> values;
// ... fill up values

if( !values.empty() )
{
    int *array = &values[0];
    for( int i = 0; i < values.size(); ++i )
    {
        int v = array[i];
        // do something with 'v'
    }
}
Martin Cote
sumber
Saya tahu bahwa Anda dalam masalah jika Anda bermutasi valuesdi dalam ifblok itu. Saya tidak tahu jawaban atas pertanyaan Anda, jadi saya hanya meninggalkan komentar. :)
Greg D
@ Greg: Masalah apa - dapatkah Anda menjelaskan sedikit?
Reunanen
Saya kira maksudnya adalah mendorong nilai baru dapat memicu "realokasi" yang akan menyebabkan array menjadi tidak valid.
Martin Cote
Panggilan yang bermutasi values, khususnya yang mengubah ukurannya (mis., push_back()), Dapat meminta realokasi vektor yang mendasari yang membatalkan penunjuk yang disalin array. Ini prinsip yang sama di belakang menggunakan vektor :: iterator alih-alih penunjuk ke vektor. :)
Greg D
1
Ya, saya meletakkan nilai `` di sekitar untuk mencoba memperjelas bahwa saya berbicara tentang kelas itu sendiri, bukan nilai yang terkandung di dalamnya. :) Penamaan yang tidak menguntungkan dan semua itu. Saya tidak berpikir itu benar-benar masalah dalam kasus umum di mana pertanyaan ini relevan - mengapa seseorang mengambil pointer ke memori, kemudian mulai menyia-nyiakan vektor daripada menggunakan pointer? Kebodohan.
Greg D

Jawaban:

118

Ini terlewatkan dari standar C ++ 98 tetapi kemudian ditambahkan sebagai bagian dari TR. Standar C ++ 0x yang akan datang tentu saja akan memuat ini sebagai persyaratan.

Dari n2798 (draf C ++ 0x):

23.2.6 Vektor template kelas [vektor]

1 Vektor adalah wadah urutan yang mendukung iterator akses acak. Selain itu, ia mendukung (diamortisasi) operasi penyisipan dan penghapusan waktu konstan di akhir; masukkan dan hapus di tengah, ambil waktu linier. Manajemen penyimpanan ditangani secara otomatis, meskipun petunjuk dapat diberikan untuk meningkatkan efisiensi. Unsur-unsur vektor disimpan secara berdekatan, artinya jika v adalah vektor di mana T adalah jenis selain bool, maka ia mematuhi identitas & v [n] == & v [0] + n untuk semua 0 <= n <v .ukuran().

dirkgently
sumber
3
Hal ini juga dinyatakan dalam ISO 14882, Edisi ke-2: Bagian 23.2.4 [lib.vector]: "Elemen-elemen vektor disimpan secara berdekatan, artinya jika v adalah vektor <T, Allocator> di mana T adalah beberapa tipe selain bool, maka itu mematuhi identitas & v [n] == & v [0] + n untuk semua 0 <= n <v.size (). "
Mike Caron
4
so s, TR, TC, :) Sebenarnya C ++ 03 juga disebut C ++ 98-TC1 (technical corrigendum) dari apa yang saya baca
Johannes Schaub - litb
2
Bagaimana dengan vektor vektor? Vektor İnner tepat setelah vektor dalam grup terakhir?
huseyin tugrul buyukisik
1
@huseyin tugrul buyukisik apakah anda mengetahui jawabannya? Saya juga bertanya-tanya bagaimana ini bekerja
David Doria
1
@huseyin tugrul buyukisik Tentu saja benar, tetapi contoh-contoh berikut std::vectorini yang berdekatan. Misalnya: dalam std::vector<std::vector<int>> velemen v[0],, v[1]... disimpan kemudian dalam memori, tetapi elemen v[0].back()dan v[1].front()tidak dijamin akan.
jarzec
27

Seperti jawaban lain yang telah ditunjukkan, konten vektor dijamin kontinu (kecuali keanehan bool).

Komentar yang ingin saya tambahkan, adalah jika Anda melakukan penyisipan atau penghapusan pada vektor, yang dapat menyebabkan vektor mengalokasikan kembali memorinya, maka Anda akan menyebabkan semua penunjuk dan iterator yang disimpan menjadi tidak valid.

Bill Lynch
sumber
1
Elemen-elemen tersebut akan tetap disimpan dalam blok memori yang berdekatan, itu hanya akan berada di tempat yang berbeda. Pertanyaannya secara khusus tentang kedekatan.
Dima
2
Tapi petunjuk dan iterator yang ada akan dibatalkan.
Bill Lynch
Poin yang bagus. Anda harus memasukkannya ke dalam jawaban Anda untuk memperjelas apa yang Anda maksud.
Dima
jawaban paling berguna bagi saya
CoffeDeveloper
Sekarang saya tahu mengapa program saya segfault kemarin, ketika saya mengulanginya dalam loop ganda menghapus elemen tertentu :) Terima kasih!
pengguna2891462
9

Standar sebenarnya menjamin bahwa a vectorkontinu dalam memori dan &a[0]dapat diteruskan ke Cfungsi yang mengharapkan sebuah array.

Pengecualian untuk aturan ini adalah vector<bool>yang hanya menggunakan satu bit per booldengan demikian meskipun ia memiliki memori berkelanjutan, ia tidak dapat digunakan sebagai bool*(ini secara luas dianggap sebagai pengoptimalan palsu dan kesalahan).

BTW, kenapa tidak Anda menggunakan iterator? Untuk itulah mereka.

Motti
sumber
1
> BTW, kenapa tidak Anda menggunakan iterator? Untuk itulah mereka. Mungkin dia membaca makalah baru Alexanrescu dengan topik: boostcon.com/site-media/var/sphene/sphwiki/attachment/2009/05/…
Nemanja Trifunovic
Terima kasih untuk tautannya, saya akan memasukkannya ke daftar bacaan saya (saya mencoba untuk tidak melewatkan artikel Alexandresu)
Motti
Mwahaha, semua orang sepertinya membicarakan tentang presentasi itu akhir-akhir ini. Lihat, diskusi masih hangat tentang itu: groups.google.com/group/comp.lang.c++.moderated/browse_thread/…
Johannes Schaub - litb
Jika Anda membacanya dengan cermat, artikel Alexandrescu tidak benar-benar mengatakan "Jangan gunakan iterator di C ++", artikel itu mengatakan "Periksa D". Pendekatan yang dia gambarkan dalam makalah itu sangat mirip dengan bahasa dan kerangka kerja yang ada yang telah menyerap warisan fungsional (Daftar, Skema, Haskell) dan saya sangat meragukan apakah sintaks berbasis C yang lain lagi adalah titik awal yang ideal untuk lebih baik. penanganan daftar. Beberapa waktu tahun lalu saya secara singkat mencoba membujuknya untuk mengubah bakatnya yang luar biasa untuk meningkatkan bahasa yang sudah mapan seperti C #, tetapi saya takut tidak berhasil! :)
Daniel Earwicker
6

Seperti yang telah dikatakan orang lain, secara vectorinternal menggunakan array objek yang berdekatan. Pointer ke dalam array itu harus diperlakukan sebagai tidak valid setiap kali ada fungsi anggota non-const yang disebut IIRC.

Namun, ada pengecualian !!

vector<bool>memiliki implementasi khusus yang dirancang untuk menghemat ruang, sehingga setiap bool hanya menggunakan satu bit. Array yang mendasari bukanlah array bool dan aritmatika array yang berdekatan vector<bool>tidak berfungsi seperti yang diharapkan vector<T>.

(Saya kira itu juga mungkin bahwa ini mungkin benar untuk setiap spesialisasi vektor, karena kita selalu dapat menerapkan yang baru. Namun, std::vector<bool>adalah satu-satunya, err, spesialisasi standar yang aritmatika penunjuk sederhana tidak akan berfungsi.)

Wuggy
sumber
Pengguna tidak diperbolehkan untuk mengkhususkan std::vector, dan semua vektor lain diperlukan untuk menggunakan penyimpanan yang berdekatan. Oleh karena itu, std::vector<bool>(untungnya) adalah satu-satunya vektor standar yang aneh. (Saya sangat berpendapat bahwa spesialisasi ini harus ditinggalkan dan diganti dengan mis. A std::dynamic_bitsetdengan banyak fungsi yang sama. Ini bukan struktur data yang buruk, ini hanya bukan vektor.)
Arne Vogel
3

Saya menemukan utas ini karena saya memiliki kasus penggunaan di mana vektor yang menggunakan memori bersebelahan adalah keuntungan.

Saya belajar bagaimana menggunakan objek buffer vertex di OpenGL. Saya membuat kelas pembungkus untuk memuat logika buffer, jadi yang perlu saya lakukan adalah melewatkan array floats dan beberapa nilai konfigurasi untuk membuat buffer. Saya ingin dapat menghasilkan buffer dari suatu fungsi berdasarkan input pengguna, sehingga panjangnya tidak diketahui pada waktu kompilasi. Melakukan sesuatu seperti ini akan menjadi solusi termudah:

void generate(std::vector<float> v)
{
  float f = generate_next_float();
  v.push_back(f);
}

Sekarang saya bisa melewatkan float vektor sebagai array ke fungsi terkait buffer OpenGL. Ini juga menghilangkan kebutuhan sizeof untuk menentukan panjang array.

Ini jauh lebih baik daripada mengalokasikan array besar untuk menyimpan float dan berharap saya membuatnya cukup besar, atau membuat array dinamis saya sendiri dengan penyimpanan yang berdekatan.

NobodyImportant
sumber
2
fungsi ini tidak masuk akal bagi saya. maksud Anda memberikan referensi atau penunjuk ke vdaripada vdirinya sendiri? karena melewatkan vsendiri akan menyebabkan salinan dibuat di dalam fungsi, yang tidak akan ada lagi setelah fungsi berakhir. Jadi Anda mendorong sesuatu ke vektor hanya untuk menghapus vektor saat fungsi berakhir.
johnbakers
1

cplusplus.com:

Kontainer vektor diimplementasikan sebagai array dinamis; Sama seperti array biasa, container vektor memiliki elemennya yang disimpan di lokasi penyimpanan yang berdekatan, yang berarti bahwa elemennya dapat diakses tidak hanya menggunakan iterator tetapi juga menggunakan offset pada pointer biasa ke elemen.

Igor Oks
sumber
1

Ya, elemen dari std :: vector dijamin bersebelahan.

Benoît
sumber
Baik. Saya kira saya menggunakan terlalu banyak :)
Benoît