Setelah banyak penyelidikan dengan valgrind, saya telah membuat kesimpulan bahwa std :: vector membuat salinan dari objek yang ingin Anda push_back.
Benarkah itu benar? Vektor tidak dapat menyimpan referensi atau penunjuk objek tanpa salinan ?!
Terima kasih
*
atau&
untuk membuat pointer atau referensi.push_back
: dibutuhkan aconst&
. Entah itu membuang nilai (tidak berguna), atau ada metode pengambilan. Jadi kita melihat tanda tangan dariback
, dan itu mengembalikan polos&
, sehingga nilai asli disalin atauconst
telah secara diam-diam dibuang (sangat buruk: perilaku yang berpotensi tidak terdefinisi). Jadi dengan asumsi para perancangvector
itu rasional (vector<bool>
tidak tahan) kami menyimpulkan itu membuat salinan.Jawaban:
Ya,
std::vector<T>::push_back()
buat salinan argumen dan simpan dalam vektor. Jika Anda ingin menyimpan pointer ke objek di vektor Anda, buatstd::vector<whatever*>
bukanstd::vector<whatever>
.Namun, Anda perlu memastikan bahwa objek yang direferensikan oleh pointer tetap valid sementara vektor memegang referensi untuk mereka (pointer pintar menggunakan idiom RAII memecahkan masalah).
sumber
push_back
akan melakukan langkah alih-alih salinan jika argumennya adalah referensi nilai. (Objek dapat dikonversi ke rvalue referensi denganstd::move()
.)emplace_back
untuk menghindari penyalinan atau pemindahan (buat objek di tempat yang disediakan oleh wadah).Ya,
std::vector
simpan salinannya. Bagaimana seharusnyavector
tahu masa hidup yang diharapkan dari objek Anda?Jika Anda ingin mentransfer atau berbagi kepemilikan objek menggunakan pointer, mungkin pointer cerdas seperti
shared_ptr
(ditemukan dalam Boost atau TR1 ) untuk memudahkan manajemen sumber daya.sumber
boost::ptr_vector
?class Foo { typedef boost::shared_ptr<Foo> ptr; };
hanya menulisFoo::ptr
.shared_ptr
tidak persis api dan lupakan. Lihat stackoverflow.com/questions/327573 dan stackoverflow.com/questions/701456Dari C ++ 11 dan seterusnya, semua kontainer standar (
std::vector
,,std::map
dll) mendukung pemindahan semantik, yang berarti bahwa Anda sekarang dapat meneruskan nilai ke kontainer standar dan menghindari salinan:Atau Anda dapat menggunakan berbagai pointer cerdas untuk mendapatkan sebagian besar efek yang sama:
std::unique_ptr
contohstd::shared_ptr
contohsumber
std::make_unique
(mengganggu) hanya tersedia di C ++ 14 dan di atas. Pastikan Anda memberi tahu kompiler Anda untuk mengatur kesesuaian standarnya jika Anda ingin mengkompilasi contoh-contoh ini.auto pFoo =
untuk menghindari pengulangan; dan semuastd::string
gips dapat dihapus (ada konversi implisit dari string literal kestd::string
)make_unique
dapat dengan mudah diimplementasikan dalam C ++ 11, jadi itu hanya sedikit gangguan bagi seseorang yang terjebak dengan kompiler C ++ 11template<typename T, typename... Args> unique_ptr<T> make_unique(Args&&... args) { return unique_ptr<T>{new T{args...}}; }
std::move()
denganstd::shared_ptr
, pointer bersama asli mungkin memiliki pointer itu berubah sejak kepemilikan diteruskan ke vektor. Lihat di sini: coliru.stacked-crooked.com/a/99d4f04f05e5c7f3std :: vector selalu membuat salinan dari apa pun yang disimpan dalam vektor.
Jika Anda menyimpan vektor pointer, maka itu akan membuat salinan dari pointer, tetapi bukan instance yang menunjuk pointer. Jika Anda berurusan dengan objek besar, Anda bisa (dan mungkin harus) selalu menggunakan vektor pointer. Seringkali, menggunakan vektor smart pointer dari tipe yang sesuai adalah baik untuk tujuan keselamatan, karena menangani masa pakai objek dan manajemen memori bisa rumit sebaliknya.
sumber
Std :: vector tidak hanya membuat salinan dari apa pun yang Anda tekan kembali, tetapi definisi dari koleksi menyatakan bahwa ia akan melakukannya, dan bahwa Anda tidak dapat menggunakan objek tanpa semantik salinan yang benar dalam vektor. Jadi, misalnya, Anda tidak menggunakan auto_ptr dalam vektor.
sumber
Relevan dalam C ++ 11 adalah
emplace
keluarga fungsi anggota, yang memungkinkan Anda mentransfer kepemilikan objek dengan memindahkannya ke dalam wadah.Ungkapan penggunaan akan terlihat seperti
Langkah untuk objek nilai adalah penting karena jika tidak maka akan diteruskan sebagai referensi atau referensi const dan langkah konstruktor tidak akan dipanggil.
sumber
jika Anda ingin bukan salinannya; maka cara terbaik adalah dengan menggunakan vektor pointer (atau struktur lain yang berfungsi untuk tujuan yang sama). jika Anda ingin salinannya; gunakan langsung push_back (). Anda tidak punya pilihan lain.
sumber
Mengapa butuh banyak penyelidikan valgrind untuk mengetahui hal ini! Buktikan saja kepada diri Anda dengan beberapa kode sederhana misalnya
Jika "hello world" dicetak, objek harus disalin
sumber