Mengapa salah menggunakan std :: auto_ptr <> dengan kontainer standar?

217

Mengapa salah menggunakan std::auto_ptr<>wadah standar?

Uhall
sumber
5
Pasti memberi +1 pada ini karena saya telah melihat begitu banyak orang yang salah. Ini pertanyaan yang bagus untuk ditanyakan.
twokats
Baca juga item terkait. Pertanyaan ini dipertimbangkan di sini dari sisi lain. Semoga bermanfaat untuk memahami lebih lanjut tentang auto_ptr dan wadah STL. stackoverflow.com/questions/8630552/…
nickolay
1
movesemantik dan unique_ptrdirancang untuk menghindari masalah yang berkaitan dengan auto_ptr. Di C ++ 03, bahasa tidak cukup kuat untuk menulis kelas seperti auto_ptritu berperilaku dengan benar dan aman di semua skenario karena kompilator dan bahasa tidak dapat membedakan nilai l dan r sehingga beberapa "peretasan" digunakan untuk mendapatkan perilaku yang diinginkan sebagian besar waktu.
Phil1970
Artikel yang bagus: Wadah STL dan Auto_ptrs - Mengapa Mereka Tidak Mencampur quantstart.com/articles/…
alfC

Jawaban:

124

Standar C ++ mengatakan bahwa elemen STL harus "copy-constructible" dan "assignable." Dengan kata lain, suatu elemen harus dapat ditugaskan atau disalin dan kedua elemen tersebut secara logis independen. std::auto_ptrtidak memenuhi persyaratan ini.

Ambil contoh kode ini:

class X
{
};

std::vector<std::auto_ptr<X> > vecX;
vecX.push_back(new X);

std::auto_ptr<X> pX = vecX[0];  // vecX[0] is assigned NULL.

Untuk mengatasi batasan ini, Anda harus menggunakan std::unique_ptr, std::shared_ptratau std::weak_ptrsmart pointer atau boost setara jika Anda tidak memiliki C ++ 11. Berikut adalah dokumentasi pendorong perpustakaan untuk petunjuk pintar ini.

Kevin
sumber
7
Anda juga harus mempertimbangkan wadah penunjuk boost, jika Anda tidak memerlukan kepemilikan bersama.
me22
4
unique_ptrjuga melarang penyalinan, sehingga operasi STL tertentu tidak akan berfungsi dengan benar kecuali mereka dapat menggunakan semantik gerakannya.
Mike Weller
4
"Untuk mengatasi batasan ini, Anda harus menggunakan std::unique_ptr": bahwa templat kelas hanya bisa ada karena memindahkan semantik (spesifikasinya memerlukan referensi nilai ulang), sehingga pada dasarnya memerlukan C ++ 11. Namun (dan terkait) Standar C ++ 11 tidak lagi mengatakan bahwa tipe elemen STL harus "copy-constructible" dan "assignable"; cukup bergerak-konstruktif dan bergerak-ditugaskan. Memang unique_ptrcontoh hanya bergerak-membangun dan memindahkan-ditugaskan. Tapi begitu juga auto_ptrcontoh! Sebagai konsekuensinya, dalam C ++ 11 Anda dapat melakukan auto_ptrapa yang dapat Anda lakukan unique_ptr.
Marc van Leeuwen
@MarcvanLeeuwen kecuali Anda resetdan releasejika diperlukan
ratchet freak
2
@ scratchetfreak: Hmm, saya tidak mengerti. Apa? "kecuali Anda resetdan release", saya tidak melihat bagaimana itu berlaku untuk apa pun dalam komentar saya. Perhatikan bahwa keduanya auto_ptrdan unique_ptrkedua metode ini, dan mereka melakukan hal yang sama dalam kedua kasus.
Marc van Leeuwen
66

The semantik copy dari auto_ptrtidak kompatibel dengan kontainer.

Secara khusus, menyalin satu auto_ptrke yang lain tidak membuat dua objek yang sama karena satu telah kehilangan kepemilikan pointer.

Lebih khusus lagi, menyalin auto_ptrpenyebab salah satu salinan untuk melepaskan pointer. Yang mana dari sisa-sisa ini dalam wadah tidak ditentukan. Oleh karena itu, Anda dapat kehilangan akses ke pointer secara acak jika Anda menyimpannya auto_ptrsdi dalam wadah.

Frank Krueger
sumber
39

Dua artikel super bagus tentang hal ini:

Lazer
sumber
Karena saya pikir dalam hampir dua tahun, dia mungkin menangani masalah yang ada.
Anak anjing
27
@DeadMG: ya, Anda benar. Tapi itu bukan tujuan saya. Jika seseorang datang ke utas ini kapan-kapan dan ingin belajar tentang sesuatu auto_ptr, tautan ini akan sangat membantu, saya yakin.
Lazer
Ada banyak duplikat yang lebih baru.
Puppy
8
@DeadMG: Pertanyaan ini tidak ditutup sebagai duplikat dan karenanya terbuka untuk ekstensi. Lazer mengatakan apa yang tidak dikatakan sebelumnya di sini. Saya kira dia datang secara kebetulan.
Sebastian Mach
Penjelasan dalam tautan kedua, yang menganalisis masalah setelah menelepon sort(), lebih jelas daripada semua jawaban di sini.
chaosink
17

Wadah STL harus dapat menyalin item yang Anda simpan di dalamnya, dan dirancang untuk mengharapkan yang asli dan salinannya setara. objek penunjuk otomatis memiliki kontrak yang sama sekali berbeda, di mana penyalinan membuat transfer kepemilikan. Ini berarti bahwa kontainer auto_ptr akan memperlihatkan perilaku aneh, tergantung penggunaan.

Ada uraian terperinci tentang apa yang salah dalam Efektif STL (Scott Meyers) item 8 dan juga deskripsi yang tidak terlalu terperinci dalam Efektif C ++ (Scott Meyers) item 13.

Garth Gilmour
sumber
12

Wadah STL menyimpan salinan barang-barang yang terkandung. Ketika auto_ptr disalin, itu menetapkan ptr lama ke nol. Banyak metode wadah rusak oleh perilaku ini.

Dustin Getz
sumber
Tetapi, ketika menggunakan unique_ptr Anda mendapatkan hal yang hampir sama karena hanya satu unique_ptr yang dapat memiliki kepemilikan objek?
Tracer
2
@ Tracer unique_ptrseperti objek C ++ 11 yang tepat hanya dapat mentransfer kepemilikan sumber dayanya ketika dipindah-bangun atau-ditugaskan, memastikan bahwa pemrogram harus dengan sengaja melewati suatu std::move(sourceObject)atau sementara, alih-alih memberikan nilai dan secara tidak sengaja / tidak terduga dimutasi oleh copy-tugas ... yang, seperti ditekankan secara menyeluruh di sini, adalah masalah inti auto_ptr.
underscore_d
4

C ++ 03 Standar (ISO-IEC 14882-2003) mengatakan dalam klausa 20.4.5 paragraf 3:

[...] [ Catatan: [...] auto_ptr tidak memenuhi persyaratan CopyConstructible dan Assignable untuk elemen kontainer Perpustakaan Standar dan dengan demikian instantiate kontainer Perpustakaan Standar dengan hasil auto_ptr dalam perilaku yang tidak ditentukan. - catatan akhir ]

Standar C ++ 11 (ISO-IEC 14882-2011) mengatakan dalam lampiran D.10.1 paragraf 3:

[...] Catatan: [...] Contoh auto_ptr memenuhi persyaratan MoveConstructible dan MoveAssignable, tetapi tidak memenuhi persyaratan CopyConstructible dan CopyAssignable. - catatan akhir]

Standar C ++ 14 (ISO-IEC 14882-2014) mengatakan dalam lampiran C.4.2 Lampiran D: fitur kompatibilitas:

Ubah : Templat kelas auto_ptr, unary_function, dan binary_function, templat fungsi random_shuffle, dan templat fungsi (dan tipe kembalinya) ptr_fun, mem_fun, mem_fun_ref, bind1st, dan bind2nd tidak didefinisikan.
Dasar Pemikiran : Digantikan oleh fitur-fitur baru.
Efek pada fitur asli : Kode C ++ 2014 yang valid yang menggunakan templat kelas dan templat fungsi ini mungkin gagal dikompilasi dalam Standar Internasional ini.

bitek
sumber