Inilah bab Alexandrescu (gratis) tentang seluk-beluk menciptakan petunjuk pintar dari berbagai rasa: informit.com/articles/article.aspx?p=31529 Dalam implementasinya, ia menggunakan argumen templat sebagai "kebijakan" untuk menentukan atribut mana yang ia inginkan ( misalnya, penghitungan referensi), sedangkan perpustakaan standar menggunakan kelas yang terpisah. Perhatikan bahwa ia juga menulis sebelum referensi nilai tersedia untuk membuat sesuatu seperti std :: unique_ptr menjadi mungkin.
logam
Saya ingin menambahkan satu poin lagi ke pertanyaan di atas, smart pointer std :: shared_ptr tidak memiliki operator subskrip dan tidak mendukung aritmatika ponter, kita dapat menggunakan get () untuk mendapatkan pointer bawaan.
suresh m
Jawaban:
1884
MEMPERBARUI
Jawaban ini agak lama, dan karenanya menggambarkan apa yang 'baik' pada saat itu, yang merupakan petunjuk cerdas yang disediakan oleh perpustakaan Boost. Sejak C ++ 11, perpustakaan standar telah menyediakan tipe smart pointer yang memadai, dan karenanya Anda harus mendukung penggunaan std::unique_ptr, std::shared_ptrdan std::weak_ptr.
Ada juga std::auto_ptr. Itu sangat mirip dengan penunjuk cakupan, kecuali bahwa ia juga memiliki kemampuan berbahaya "khusus" untuk disalin - yang juga secara tak terduga mengalihkan kepemilikan. Itu sudah ditinggalkan di C ++ 11 dan dihapus di C ++ 17 , jadi Anda tidak harus menggunakannya.
std::auto_ptr<MyObject> p1 (newMyObject());
std::auto_ptr<MyObject> p2 = p1;// Copy and transfer ownership. // p1 gets set to empty!
p2->DoSomething();// Works.
p1->DoSomething();// Oh oh. Hopefully raises some NULL pointer exception.
JAWABAN TUA
Pointer pintar adalah kelas yang membungkus pointer C ++ 'mentah' (atau 'telanjang'), untuk mengatur masa pakai objek yang ditunjuk. Tidak ada satu pun tipe smart pointer, tetapi semuanya mencoba untuk abstrak sebuah pointer mentah dengan cara yang praktis.
Pointer pintar harus lebih disukai daripada pointer mentah. Jika Anda merasa perlu menggunakan pointer (pertimbangkan terlebih dahulu jika benar - benar melakukannya), Anda biasanya ingin menggunakan pointer pintar karena ini dapat meringankan banyak masalah dengan pointer mentah, terutama lupa untuk menghapus objek dan memori yang bocor.
Dengan pointer mentah, programmer harus secara eksplisit menghancurkan objek ketika tidak lagi berguna.
// Need to create the object to achieve some goalMyObject* ptr =newMyObject();
ptr->DoSomething();// Use the object in some waydelete ptr;// Destroy the object. Done with it.// Wait, what if DoSomething() raises an exception...?
Pointer pintar dengan perbandingan mendefinisikan kebijakan kapan objek dihancurkan. Anda masih harus membuat objek, tetapi Anda tidak perlu lagi khawatir untuk menghancurkannya.
SomeSmartPtr<MyObject> ptr(newMyObject());
ptr->DoSomething();// Use the object in some way.// Destruction of the object happens, depending // on the policy the smart pointer class uses.// Destruction would happen even if DoSomething() // raises an exception
Kebijakan paling sederhana yang digunakan melibatkan ruang lingkup objek pembungkus penunjuk pintar, seperti yang diterapkan oleh boost::scoped_ptratau std::unique_ptr.
void f(){{
std::unique_ptr<MyObject> ptr(newMyObject());
ptr->DoSomethingUseful();}// ptr goes out of scope -- // the MyObject is automatically destroyed.// ptr->Oops(); // Compile error: "ptr" not defined// since it is no longer in scope.}
Perhatikan bahwa std::unique_ptrinstance tidak dapat disalin. Ini mencegah penunjuk dihapus beberapa kali (salah). Namun, Anda dapat meneruskan referensi ke fungsi lain yang Anda panggil.
std::unique_ptrs berguna ketika Anda ingin mengikat masa pakai objek ke blok kode tertentu, atau jika Anda menyematkannya sebagai data anggota di dalam objek lain, masa pakai objek lain itu. Objek ada sampai blok kode yang berisi keluar, atau sampai objek yang berisi itu sendiri dihancurkan.
Kebijakan smart pointer yang lebih kompleks melibatkan referensi penghitungan pointer. Ini memungkinkan pointer untuk disalin. Ketika "referensi" terakhir ke objek dihancurkan, objek tersebut dihapus. Kebijakan ini diterapkan oleh boost::shared_ptrdan std::shared_ptr.
void f(){typedef std::shared_ptr<MyObject>MyObjectPtr;// nice short aliasMyObjectPtr p1;// Empty{MyObjectPtr p2(newMyObject());// There is now one "reference" to the created object
p1 = p2;// Copy the pointer.// There are now two references to the object.}// p2 is destroyed, leaving one reference to the object.}// p1 is destroyed, leaving a reference count of zero. // The object is deleted.
Referensi penghitung referensi sangat berguna ketika masa pakai objek Anda jauh lebih rumit, dan tidak terikat langsung ke bagian kode tertentu atau ke objek lain.
Ada satu kelemahan dari referensi penghitung referensi - kemungkinan membuat referensi yang menggantung:
// Create the smart pointer on the heapMyObjectPtr* pp =newMyObjectPtr(newMyObject())// Hmm, we forgot to destroy the smart pointer,// because of that, the object is never destroyed!
Kemungkinan lain adalah membuat referensi melingkar:
structOwner{
std::shared_ptr<Owner> other;};
std::shared_ptr<Owner> p1 (newOwner());
std::shared_ptr<Owner> p2 (newOwner());
p1->other = p2;// p1 references p2
p2->other = p1;// p2 references p1// Oops, the reference count of of p1 and p2 never goes to zero!// The objects are never destroyed!
Untuk mengatasi masalah ini, Boost dan C ++ 11 telah mendefinisikan a weak_ptruntuk mendefinisikan referensi lemah (tidak terhitung) ke a shared_ptr.
Apakah maksud Anda std::auto_ptr<MyObject> p1 (new MyObject());alih-alih std::auto_ptr<MyObject> p1 (new Owner());?
Mateen Ulhaq
35
Jawaban yang luar biasa. Akan lebih baik jika diperbarui untuk c ++ 11. Saya menemukan jawaban ini mencari info tentang standar 11 baru dan alangkah baiknya jika pengunjung masa depan dapat menemukan info yang diperbarui. Saya tahu auto_ptr telah ditinggalkan. Saya percaya shated_ptr dan lemah_ptr ada seperti yang dijelaskan, dan saya pikir scoped_ptr sekarang unique_ptr dalam standar. Jika ini benar, bisakah jawaban ini diperbarui?
SaulBack
16
Mengatakan bahwa kemungkinan membuat referensi yang menggantung adalah kelemahan dari referensi yang dihitung adalah benar-benar gila. Referensi menggantung yang mungkin adalah kelemahan dari setiap pointer C ++ . Bahkan, justru kekurangan itulah yang dimaksudkan untuk diringankan oleh pointer cerdas .
Michael Dorst
16
Jika Anda mendeklarasikan pointer ke smart pointer (seperti yang dilakukan pada contoh) Anda dengan sadar melepaskan semua manfaat dari smart pointer. Ini bukan kelemahan atau cacat desain, ini adalah penggunaan paling konyol yang bisa dibayangkan.
Michael Dorst
3
A const std::auto_ptraman digunakan, jika Anda terjebak dengan C ++ 03. Saya menggunakannya untuk pola jerawat cukup banyak sampai saya mendapat akses ke C ++ 11.
Toby Speight
303
Inilah jawaban sederhana untuk C ++ modern hari ini (C ++ 11 dan yang lebih baru):
Apa itu smart pointer?
Ini adalah tipe yang nilainya dapat digunakan seperti pointer, tetapi yang menyediakan fitur tambahan manajemen memori otomatis: Ketika pointer cerdas tidak lagi digunakan, memori yang ditunjuknya akan dibatalkan alokasi (lihat juga definisi yang lebih rinci tentang Wikipedia ).
Kapan saya harus menggunakannya?
Dalam kode yang melibatkan pelacakan kepemilikan sepotong memori, mengalokasikan atau menghapus alokasi; penunjuk pintar sering menghemat kebutuhan Anda untuk melakukan hal-hal ini secara eksplisit.
Tapi smart pointer mana yang harus saya gunakan dalam kasus mana?
Gunakan std::unique_ptrsaat Anda tidak berniat menyimpan beberapa referensi ke objek yang sama. Misalnya, gunakan untuk penunjuk ke memori yang akan dialokasikan saat memasukkan beberapa cakupan dan tidak dialokasikan saat keluar dari ruang lingkup.
Gunakan std::shared_ptrketika Anda ingin merujuk ke objek Anda dari berbagai tempat - dan tidak ingin objek Anda tidak dialokasikan sampai semua referensi itu sendiri hilang.
Gunakan std::weak_ptrketika Anda ingin merujuk objek Anda dari berbagai tempat - untuk referensi yang tidak boleh diabaikan dan tidak dialokasikan (jadi mereka hanya akan mencatat objek tersebut hilang ketika Anda mencoba melakukan dereferensi).
Jangan gunakan boost::smart pointer atau std::auto_ptrkecuali dalam kasus khusus yang dapat Anda baca jika Anda harus.
Hei, aku tidak bertanya yang mana yang harus digunakan!
Ah, tapi kamu benar-benar ingin, mengakuinya.
Jadi kapan saya harus menggunakan pointer biasa?
Sebagian besar dalam kode yang tidak menyadari kepemilikan memori. Ini biasanya berada dalam fungsi yang mendapatkan pointer dari tempat lain dan tidak mengalokasikan atau menghapus alokasi, dan tidak menyimpan salinan pointer yang bertahan lebih lama dari eksekusi mereka.
Perlu dicatat bahwa meskipun pointer pintar (memiliki) membantu dengan manajemen memori yang tepat, pointer mentah (tidak memiliki) masih berguna untuk keperluan organisasi lainnya dalam struktur data. Herb Sutter memberikan presentasi yang bagus tentang masalah ini di CppCon 2016, yang dapat Anda lihat di YouTube: Kebocoran Kebebasan dalam C ++ ... Secara Default.
wiktor.wandachowicz
1
@ wiktor.wandachowicz T*adalah untuk std::unique_ptr<T>apa std::weak_ptr<T>adalah untukstd::shared_ptr<T>
Caleth
@ Caleth: Tidak, saya tidak akan mengatakan itu.
einpoklum
1
@TonyTannous: Dengan hormat - Itu adalah suntingan utama; dan saya tidak merasakan jawaban saya, yang abstrak, membutuhkannya. Saya sarankan Anda menjadikan contoh jawaban terpisah, di tautannya dalam komentar.
einpoklum
112
Smart pointer adalah tipe mirip-pointer dengan beberapa fungsi tambahan, misal penghentian memori otomatis, penghitungan referensi dll.
Salah satu tipe smart-pointer sederhana adalah std::auto_ptr(bab 20.4.5 dari standar C ++), yang memungkinkan untuk mendeallocate memori secara otomatis ketika berada di luar ruang lingkup dan yang lebih kuat daripada penggunaan pointer sederhana ketika pengecualian dilemparkan, meskipun kurang fleksibel.
Tipe nyaman lainnya adalah boost::shared_ptryang mengimplementasikan penghitungan referensi dan secara otomatis mendelokasi memori ketika tidak ada referensi ke objek. Ini membantu menghindari kebocoran memori dan mudah digunakan untuk mengimplementasikan RAII .
Peringatan std::auto_ptrsudah usang dan sangat tidak disarankan karena Anda dapat secara tidak sengaja mentransfer kepemilikan. - C ++ 11 menghilangkan kebutuhan Boost, penggunaan: std::unique_ptr, std::shared_ptrdanstd::weak_ptr
ninMonkey
42
Definisi yang diberikan oleh Chris, Sergdev dan Llyod benar. Saya lebih suka definisi yang lebih sederhana, hanya untuk membuat hidup saya sederhana: Penunjuk pintar hanyalah sebuah kelas yang membebani -> dan *operator. Yang berarti bahwa objek Anda secara semantik terlihat seperti sebuah pointer tetapi Anda dapat membuatnya melakukan hal-hal yang lebih dingin, termasuk penghitungan referensi, penghancuran otomatis, dll.
shared_ptrDan auto_ptrcukup dalam banyak kasus, tetapi datang bersama dengan seperangkat keanehan kecil mereka sendiri.
Pointer pintar seperti pointer biasa (diketik), seperti "char *", kecuali ketika pointer itu sendiri keluar dari ruang lingkup maka apa yang menunjuk ke dihapus juga. Anda dapat menggunakannya seperti menggunakan pointer biasa, dengan menggunakan "->", tetapi tidak jika Anda membutuhkan pointer aktual ke data. Untuk itu, Anda dapat menggunakan "& * ptr".
Ini berguna untuk:
Objek yang harus dialokasikan dengan yang baru, tetapi Anda ingin memiliki masa hidup yang sama dengan sesuatu di tumpukan itu. Jika objek ditugaskan ke penunjuk pintar, maka mereka akan dihapus ketika program keluar dari fungsi / blok itu.
Anggota data kelas, sehingga ketika objek dihapus semua data yang dimiliki juga dihapus, tanpa kode khusus di destructor (Anda harus memastikan destructor adalah virtual, yang hampir selalu merupakan hal yang baik untuk dilakukan) .
Anda mungkin tidak ingin menggunakan penunjuk pintar saat:
... pointer seharusnya tidak benar-benar memiliki data ... yaitu, ketika Anda hanya menggunakan data, tetapi Anda ingin itu bertahan dari fungsi di mana Anda mereferensikannya.
... smart pointer itu sendiri tidak akan dihancurkan di beberapa titik. Anda tidak ingin itu berada di memori yang tidak pernah dihancurkan (seperti pada objek yang dialokasikan secara dinamis tetapi tidak akan dihapus secara eksplisit).
... dua pointer cerdas mungkin menunjuk ke data yang sama. (Namun, ada pointer lebih pintar yang akan menangani itu ... yang disebut penghitungan referensi .)
Kebanyakan jenis pointer pintar menangani membuang objek pointer-to untuk Anda. Ini sangat berguna karena Anda tidak perlu berpikir tentang membuang benda secara manual lagi.
Pointer pintar yang paling umum digunakan adalah std::tr1::shared_ptr (atau boost::shared_ptr), dan, lebih jarang std::auto_ptr,. Saya merekomendasikan penggunaan regulershared_ptr .
shared_ptrsangat fleksibel dan berhubungan dengan berbagai macam skenario pembuangan, termasuk kasus di mana objek perlu "melewati batas DLL" (kasus mimpi buruk umum jika berbeda libcdigunakan antara kode Anda dan DLL).
Smart pointer adalah objek yang bertindak seperti pointer, tetapi juga memberikan kontrol pada konstruksi, penghancuran, penyalinan, pemindahan, dan dereferencing.
Seseorang dapat mengimplementasikan smart pointer sendiri, tetapi banyak perpustakaan juga menyediakan implementasi smart pointer masing-masing dengan kelebihan dan kekurangan yang berbeda.
Misalnya, Boost menyediakan implementasi smart pointer berikut:
shared_ptr<T>adalah pointer untuk Tmenggunakan jumlah referensi untuk menentukan kapan objek tidak lagi dibutuhkan.
scoped_ptr<T>adalah pointer yang dihapus secara otomatis ketika keluar dari ruang lingkup. Tidak ada tugas yang memungkinkan.
intrusive_ptr<T>adalah pointer penghitung referensi lain. Ini memberikan kinerja yang lebih baik daripada shared_ptr, tetapi membutuhkan jenis Tuntuk menyediakan mekanisme penghitungan referensi sendiri.
weak_ptr<T>adalah penunjuk yang lemah, bekerja bersamaan dengan shared_ptruntuk menghindari referensi melingkar.
shared_array<T>seperti shared_ptr, tetapi untuk array T.
scoped_array<T>seperti scoped_ptr, tetapi untuk array T.
Ini hanya satu deskripsi linear dari masing-masing dan dapat digunakan sesuai kebutuhan, untuk detail lebih lanjut dan contoh orang dapat melihat dokumentasi Boost.
Selain itu, pustaka standar C ++ menyediakan tiga pointer cerdas; std::unique_ptruntuk kepemilikan yang unik, std::shared_ptruntuk kepemilikan bersama dan std::weak_ptr. std::auto_ptrada di C ++ 03 tetapi sekarang sudah usang.
Pointer pintar adalah objek yang bertindak, terlihat dan terasa seperti pointer normal tetapi menawarkan lebih banyak fungsi. Di C ++, smart pointer diimplementasikan sebagai kelas templat yang merangkum sebuah pointer dan menimpa operator pointer standar. Mereka memiliki sejumlah keunggulan dibandingkan pointer biasa. Mereka dijamin diinisialisasi sebagai null pointer atau pointer ke objek tumpukan. Peniruan melalui pointer nol diperiksa. Tidak perlu menghapus. Objek secara otomatis dibebaskan ketika pointer terakhir ke mereka telah pergi. Satu masalah signifikan dengan pointer cerdas ini adalah bahwa tidak seperti pointer biasa, mereka tidak menghormati warisan. Pointer pintar tidak menarik untuk kode polimorfik. Diberikan di bawah ini adalah contoh untuk penerapan smart pointer.
Contoh:
template<class X>class smart_pointer
{public:
smart_pointer();// makes a null pointer
smart_pointer(const X& x)// makes pointer to copy of x
X&operator*();const X&operator*()const;
X*operator->()const;
smart_pointer(const smart_pointer <X>&);const smart_pointer <X>&operator=(const smart_pointer<X>&);~smart_pointer();private://...};
Kelas ini menerapkan pointer pintar ke objek tipe X. Objek itu sendiri terletak di heap. Berikut cara menggunakannya:
Dalam ilmu komputer, penunjuk cerdas adalah tipe data abstrak yang mensimulasikan penunjuk sambil memberikan fitur tambahan, seperti pengumpulan sampah otomatis atau pemeriksaan batas. Fitur tambahan ini dimaksudkan untuk mengurangi bug yang disebabkan oleh penyalahgunaan pointer sambil mempertahankan efisiensi. Pointer pintar biasanya melacak objek yang menunjuk mereka untuk tujuan manajemen memori. Penyalahgunaan pointer adalah sumber utama bug: alokasi konstan, deallokasi dan referensi yang harus dilakukan oleh program yang ditulis menggunakan pointer membuatnya sangat mungkin bahwa beberapa kebocoran memori akan terjadi. Pointer pintar mencoba untuk mencegah kebocoran memori dengan membuat sumber daya otomatis: ketika pointer ke objek (atau yang terakhir dalam serangkaian pointer) dihancurkan,
Biarkan T menjadi kelas dalam tutorial ini. Petunjuk dalam C ++ dapat dibagi menjadi 3 jenis:
1) Petunjuk mentah :
T a;
T * _ptr =&a;
Mereka memegang alamat memori ke lokasi di memori. Gunakan dengan hati-hati, karena program menjadi rumit sulit untuk dilacak.
Pointer dengan data atau alamat const {Baca mundur}
T a ;const T * ptr1 =&a ;
T const* ptr1 =&a ;
Pointer ke tipe data T yang merupakan const. Berarti Anda tidak dapat mengubah tipe data menggunakan pointer. yaitu *ptr1 = 19; tidak akan bekerja. Tapi Anda bisa memindahkan pointer. yaitu ptr1++ , ptr1--; dll akan bekerja. Baca mundur: pointer ke tipe T yang merupakan const
T *const ptr2 ;
Pointer const ke tipe data T. Berarti Anda tidak dapat memindahkan pointer tetapi Anda dapat mengubah nilai yang ditunjuk oleh pointer. yaitu *ptr2 = 19akan bekerja tetapi ptr2++ ; ptr2--dll tidak akan bekerja. Baca mundur: pointer pointer ke tipe T
const T *const ptr3 ;
Pointer const ke tipe data const T. Berarti Anda tidak bisa menggerakkan pointer juga tidak bisa mengubah pointer tipe data menjadi pointer. yaitu. ptr3-- ; ptr3++ ; *ptr3 = 19;tidak akan bekerja
3) Smart Pointers : { #include <memory>}
Pointer Bersama :
T a ;//shared_ptr<T> shptr(new T) ; not recommended but works
shared_ptr<T> shptr = make_shared<T>();// faster + exception safe
std::cout << shptr.use_count();// 1 // gives the number of "
things " pointing to it.
T * temp = shptr.get();// gives a pointer to object// shared_pointer used like a regular pointer to call member functions
shptr->memFn();(*shptr).memFn();//
shptr.reset();// frees the object pointed to be the ptr
shptr =nullptr;// frees the object
shptr = make_shared<T>();// frees the original object and points to new object
Diimplementasikan menggunakan penghitungan referensi untuk melacak berapa banyak "hal" menunjuk ke objek yang ditunjuk oleh pointer. Ketika jumlah ini masuk ke 0, objek dihapus secara otomatis, yaitu keberatan dihapus ketika semua share_ptr yang menunjuk ke objek keluar dari ruang lingkup. Ini menghilangkan sakit kepala karena harus menghapus objek yang telah Anda alokasikan menggunakan yang baru.
Weak Pointer:
Membantu menangani referensi siklik yang muncul saat menggunakan Shared Pointer Jika Anda memiliki dua objek yang ditunjuk oleh dua pointer bersama dan ada internal pointer bersama menunjuk satu sama lain bersama pointer maka akan ada referensi siklik dan objek tidak akan dihapus ketika pointer bersama keluar dari ruang lingkup. Untuk mengatasi ini, ubah anggota internal dari shared_ptr menjadi kelemahan_ptr. Catatan: Untuk mengakses elemen yang ditunjuk oleh penunjuk lemah gunakan kunci (), ini mengembalikan melemah_ptr.
T a ;
shared_ptr<T> shr = make_shared<T>();
weak_ptr<T> wk = shr ;// initialize a weak_ptr from a shared_ptr
wk.lock()->memFn();// use lock to get a shared_ptr // ^^^ Can lead to exception if the shared ptr has gone out of scopeif(!wk.expired()) wk.lock()->memFn();// Check if shared ptr has gone out of scope before access
Pointer Unik: Pointer
pintar ringan dengan kepemilikan eksklusif. Gunakan saat penunjuk menunjuk ke objek unik tanpa berbagi objek di antara pointer.
unique_ptr<T> uptr(new T);
uptr->memFn();//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset();// deletes the object pointed to by uptr
Untuk mengubah objek yang ditunjuk oleh ptr unik, gunakan pindahkan semantik
unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1);// object pointed by uptr2 is deleted and // object pointed by uptr1 is pointed to by uptr2// uptr1 becomes null
Referensi: Mereka pada dasarnya dapat dianggap sebagai const pointer, yaitu pointer yang merupakan const dan tidak dapat dipindahkan dengan sintaks yang lebih baik.
r-value reference : reference to a temporary object
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified
Pointer pintar adalah kelas, pembungkus pointer normal. Tidak seperti pointer normal, lingkaran kehidupan titik pintar didasarkan pada jumlah referensi (berapa kali objek penunjuk pintar ditugaskan). Jadi, setiap kali pointer cerdas ditugaskan ke yang lain, referensi internal akan menghitung plus plus. Dan setiap kali objek keluar dari ruang lingkup, jumlah referensi dikurangi minus.
Pointer otomatis, meskipun terlihat serupa, sama sekali berbeda dari smart pointer. Ini adalah kelas yang mudah digunakan yang tidak menggunakan sumber daya kapan pun objek pointer otomatis keluar dari ruang lingkup variabel. Sampai batas tertentu, itu membuat pointer (ke memori yang dialokasikan secara dinamis) bekerja mirip dengan variabel stack (dialokasikan secara statis dalam waktu kompilasi).
Smart Pointer adalah di mana Anda tidak perlu khawatir tentang De-Alokasi Memori, Berbagi Sumber Daya, dan Transfer.
Anda dapat menggunakan pointer ini dengan sangat baik dengan cara yang sama seperti alokasi bekerja di Jawa. Di java Sampah Kolektor melakukan trik, sedangkan di Smart Pointers, trik tersebut dilakukan oleh Destructors.
Jawaban yang ada bagus tetapi tidak mencakup apa yang harus dilakukan ketika smart pointer bukan jawaban (lengkap) untuk masalah yang Anda coba selesaikan.
Antara lain (dijelaskan dengan baik dalam jawaban lain) menggunakan smart pointer adalah solusi yang memungkinkan untuk Bagaimana kita menggunakan kelas abstrak sebagai tipe fungsi kembali? yang telah ditandai sebagai duplikat dari pertanyaan ini. Namun, pertanyaan pertama yang ditanyakan apakah tergoda untuk menentukan kelas dasar abstrak (atau bahkan, ada) sebagai tipe pengembalian dalam C ++ adalah "apa maksudmu sebenarnya?". Ada diskusi yang baik (dengan referensi lebih lanjut) pemrograman berorientasi objek idiomatik dalam C ++ (dan bagaimana hal ini berbeda dengan bahasa lain) dalam dokumentasi perpustakaan penambah penunjuk arah. Singkatnya, di C ++ Anda harus memikirkan kepemilikan. Pointer pintar mana yang membantu Anda, tetapi bukan satu-satunya solusi, atau selalu merupakan solusi lengkap (mereka tidak memberi Anda salinan polimorfik) dan tidak selalu merupakan solusi yang ingin Anda paparkan di antarmuka Anda (dan pengembalian fungsi terdengar mengerikan. banyak seperti antarmuka). Mungkin cukup untuk mengembalikan referensi, misalnya. Tetapi dalam semua kasus ini (penunjuk pintar, penunjuk wadah atau hanya mengembalikan referensi) Anda telah mengubah pengembalian dari nilai ke beberapa bentuk referensi . Jika Anda benar-benar perlu menyalin, Anda mungkin perlu menambahkan "idiom" boilerplate atau beralih melampaui OO idiomatik (atau sebaliknya) di C ++ ke polimorfisme yang lebih umum menggunakan perpustakaan seperti Adobe Poly atau Boost.TypeErasure.
Jawaban:
MEMPERBARUI
Jawaban ini agak lama, dan karenanya menggambarkan apa yang 'baik' pada saat itu, yang merupakan petunjuk cerdas yang disediakan oleh perpustakaan Boost. Sejak C ++ 11, perpustakaan standar telah menyediakan tipe smart pointer yang memadai, dan karenanya Anda harus mendukung penggunaan
std::unique_ptr
,std::shared_ptr
danstd::weak_ptr
.Ada juga
std::auto_ptr
. Itu sangat mirip dengan penunjuk cakupan, kecuali bahwa ia juga memiliki kemampuan berbahaya "khusus" untuk disalin - yang juga secara tak terduga mengalihkan kepemilikan.Itu sudah ditinggalkan di C ++ 11 dan dihapus di C ++ 17 , jadi Anda tidak harus menggunakannya.
JAWABAN TUA
Pointer pintar adalah kelas yang membungkus pointer C ++ 'mentah' (atau 'telanjang'), untuk mengatur masa pakai objek yang ditunjuk. Tidak ada satu pun tipe smart pointer, tetapi semuanya mencoba untuk abstrak sebuah pointer mentah dengan cara yang praktis.
Pointer pintar harus lebih disukai daripada pointer mentah. Jika Anda merasa perlu menggunakan pointer (pertimbangkan terlebih dahulu jika benar - benar melakukannya), Anda biasanya ingin menggunakan pointer pintar karena ini dapat meringankan banyak masalah dengan pointer mentah, terutama lupa untuk menghapus objek dan memori yang bocor.
Dengan pointer mentah, programmer harus secara eksplisit menghancurkan objek ketika tidak lagi berguna.
Pointer pintar dengan perbandingan mendefinisikan kebijakan kapan objek dihancurkan. Anda masih harus membuat objek, tetapi Anda tidak perlu lagi khawatir untuk menghancurkannya.
Kebijakan paling sederhana yang digunakan melibatkan ruang lingkup objek pembungkus penunjuk pintar, seperti yang diterapkan oleh
boost::scoped_ptr
ataustd::unique_ptr
.Perhatikan bahwa
std::unique_ptr
instance tidak dapat disalin. Ini mencegah penunjuk dihapus beberapa kali (salah). Namun, Anda dapat meneruskan referensi ke fungsi lain yang Anda panggil.std::unique_ptr
s berguna ketika Anda ingin mengikat masa pakai objek ke blok kode tertentu, atau jika Anda menyematkannya sebagai data anggota di dalam objek lain, masa pakai objek lain itu. Objek ada sampai blok kode yang berisi keluar, atau sampai objek yang berisi itu sendiri dihancurkan.Kebijakan smart pointer yang lebih kompleks melibatkan referensi penghitungan pointer. Ini memungkinkan pointer untuk disalin. Ketika "referensi" terakhir ke objek dihancurkan, objek tersebut dihapus. Kebijakan ini diterapkan oleh
boost::shared_ptr
danstd::shared_ptr
.Referensi penghitung referensi sangat berguna ketika masa pakai objek Anda jauh lebih rumit, dan tidak terikat langsung ke bagian kode tertentu atau ke objek lain.
Ada satu kelemahan dari referensi penghitung referensi - kemungkinan membuat referensi yang menggantung:
Kemungkinan lain adalah membuat referensi melingkar:
Untuk mengatasi masalah ini, Boost dan C ++ 11 telah mendefinisikan a
weak_ptr
untuk mendefinisikan referensi lemah (tidak terhitung) ke ashared_ptr
.sumber
std::auto_ptr<MyObject> p1 (new MyObject());
alih-alihstd::auto_ptr<MyObject> p1 (new Owner());
?const std::auto_ptr
aman digunakan, jika Anda terjebak dengan C ++ 03. Saya menggunakannya untuk pola jerawat cukup banyak sampai saya mendapat akses ke C ++ 11.Inilah jawaban sederhana untuk C ++ modern hari ini (C ++ 11 dan yang lebih baru):
Ini adalah tipe yang nilainya dapat digunakan seperti pointer, tetapi yang menyediakan fitur tambahan manajemen memori otomatis: Ketika pointer cerdas tidak lagi digunakan, memori yang ditunjuknya akan dibatalkan alokasi (lihat juga definisi yang lebih rinci tentang Wikipedia ).
Dalam kode yang melibatkan pelacakan kepemilikan sepotong memori, mengalokasikan atau menghapus alokasi; penunjuk pintar sering menghemat kebutuhan Anda untuk melakukan hal-hal ini secara eksplisit.
std::unique_ptr
saat Anda tidak berniat menyimpan beberapa referensi ke objek yang sama. Misalnya, gunakan untuk penunjuk ke memori yang akan dialokasikan saat memasukkan beberapa cakupan dan tidak dialokasikan saat keluar dari ruang lingkup.std::shared_ptr
ketika Anda ingin merujuk ke objek Anda dari berbagai tempat - dan tidak ingin objek Anda tidak dialokasikan sampai semua referensi itu sendiri hilang.std::weak_ptr
ketika Anda ingin merujuk objek Anda dari berbagai tempat - untuk referensi yang tidak boleh diabaikan dan tidak dialokasikan (jadi mereka hanya akan mencatat objek tersebut hilang ketika Anda mencoba melakukan dereferensi).boost::
smart pointer ataustd::auto_ptr
kecuali dalam kasus khusus yang dapat Anda baca jika Anda harus.Ah, tapi kamu benar-benar ingin, mengakuinya.
Sebagian besar dalam kode yang tidak menyadari kepemilikan memori. Ini biasanya berada dalam fungsi yang mendapatkan pointer dari tempat lain dan tidak mengalokasikan atau menghapus alokasi, dan tidak menyimpan salinan pointer yang bertahan lebih lama dari eksekusi mereka.
sumber
T*
adalah untukstd::unique_ptr<T>
apastd::weak_ptr<T>
adalah untukstd::shared_ptr<T>
Smart pointer adalah tipe mirip-pointer dengan beberapa fungsi tambahan, misal penghentian memori otomatis, penghitungan referensi dll.
Intro kecil tersedia di halaman Smart Pointers - What, Why, Which? .
Salah satu tipe smart-pointer sederhana adalah
std::auto_ptr
(bab 20.4.5 dari standar C ++), yang memungkinkan untuk mendeallocate memori secara otomatis ketika berada di luar ruang lingkup dan yang lebih kuat daripada penggunaan pointer sederhana ketika pengecualian dilemparkan, meskipun kurang fleksibel.Tipe nyaman lainnya adalah
boost::shared_ptr
yang mengimplementasikan penghitungan referensi dan secara otomatis mendelokasi memori ketika tidak ada referensi ke objek. Ini membantu menghindari kebocoran memori dan mudah digunakan untuk mengimplementasikan RAII .Subjek dibahas secara mendalam dalam buku "C ++ Templates: The Complete Guide" oleh David Vandevoorde, Nicolai M. Josuttis , bab Bab 20. Smart Pointers. Beberapa topik yang dibahas:
sumber
std::auto_ptr
sudah usang dan sangat tidak disarankan karena Anda dapat secara tidak sengaja mentransfer kepemilikan. - C ++ 11 menghilangkan kebutuhan Boost, penggunaan:std::unique_ptr
,std::shared_ptr
danstd::weak_ptr
Definisi yang diberikan oleh Chris, Sergdev dan Llyod benar. Saya lebih suka definisi yang lebih sederhana, hanya untuk membuat hidup saya sederhana: Penunjuk pintar hanyalah sebuah kelas yang membebani
->
dan*
operator. Yang berarti bahwa objek Anda secara semantik terlihat seperti sebuah pointer tetapi Anda dapat membuatnya melakukan hal-hal yang lebih dingin, termasuk penghitungan referensi, penghancuran otomatis, dll.shared_ptr
Danauto_ptr
cukup dalam banyak kasus, tetapi datang bersama dengan seperangkat keanehan kecil mereka sendiri.sumber
Pointer pintar seperti pointer biasa (diketik), seperti "char *", kecuali ketika pointer itu sendiri keluar dari ruang lingkup maka apa yang menunjuk ke dihapus juga. Anda dapat menggunakannya seperti menggunakan pointer biasa, dengan menggunakan "->", tetapi tidak jika Anda membutuhkan pointer aktual ke data. Untuk itu, Anda dapat menggunakan "& * ptr".
Ini berguna untuk:
Objek yang harus dialokasikan dengan yang baru, tetapi Anda ingin memiliki masa hidup yang sama dengan sesuatu di tumpukan itu. Jika objek ditugaskan ke penunjuk pintar, maka mereka akan dihapus ketika program keluar dari fungsi / blok itu.
Anggota data kelas, sehingga ketika objek dihapus semua data yang dimiliki juga dihapus, tanpa kode khusus di destructor (Anda harus memastikan destructor adalah virtual, yang hampir selalu merupakan hal yang baik untuk dilakukan) .
Anda mungkin tidak ingin menggunakan penunjuk pintar saat:
Lihat juga:
sumber
Kebanyakan jenis pointer pintar menangani membuang objek pointer-to untuk Anda. Ini sangat berguna karena Anda tidak perlu berpikir tentang membuang benda secara manual lagi.
Pointer pintar yang paling umum digunakan adalah
std::tr1::shared_ptr
(atauboost::shared_ptr
), dan, lebih jarangstd::auto_ptr
,. Saya merekomendasikan penggunaan regulershared_ptr
.shared_ptr
sangat fleksibel dan berhubungan dengan berbagai macam skenario pembuangan, termasuk kasus di mana objek perlu "melewati batas DLL" (kasus mimpi buruk umum jika berbedalibc
digunakan antara kode Anda dan DLL).sumber
Smart pointer adalah objek yang bertindak seperti pointer, tetapi juga memberikan kontrol pada konstruksi, penghancuran, penyalinan, pemindahan, dan dereferencing.
Seseorang dapat mengimplementasikan smart pointer sendiri, tetapi banyak perpustakaan juga menyediakan implementasi smart pointer masing-masing dengan kelebihan dan kekurangan yang berbeda.
Misalnya, Boost menyediakan implementasi smart pointer berikut:
shared_ptr<T>
adalah pointer untukT
menggunakan jumlah referensi untuk menentukan kapan objek tidak lagi dibutuhkan.scoped_ptr<T>
adalah pointer yang dihapus secara otomatis ketika keluar dari ruang lingkup. Tidak ada tugas yang memungkinkan.intrusive_ptr<T>
adalah pointer penghitung referensi lain. Ini memberikan kinerja yang lebih baik daripadashared_ptr
, tetapi membutuhkan jenisT
untuk menyediakan mekanisme penghitungan referensi sendiri.weak_ptr<T>
adalah penunjuk yang lemah, bekerja bersamaan denganshared_ptr
untuk menghindari referensi melingkar.shared_array<T>
sepertishared_ptr
, tetapi untuk arrayT
.scoped_array<T>
sepertiscoped_ptr
, tetapi untuk arrayT
.Ini hanya satu deskripsi linear dari masing-masing dan dapat digunakan sesuai kebutuhan, untuk detail lebih lanjut dan contoh orang dapat melihat dokumentasi Boost.
Selain itu, pustaka standar C ++ menyediakan tiga pointer cerdas;
std::unique_ptr
untuk kepemilikan yang unik,std::shared_ptr
untuk kepemilikan bersama danstd::weak_ptr
.std::auto_ptr
ada di C ++ 03 tetapi sekarang sudah usang.sumber
scoped_ptr
tidak seperti yang dideklarasikan secara lokalconst unique_ptr
- yang juga dihapus saat keluar dari ruang lingkup.Inilah Tautan untuk jawaban serupa: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
Pointer pintar adalah objek yang bertindak, terlihat dan terasa seperti pointer normal tetapi menawarkan lebih banyak fungsi. Di C ++, smart pointer diimplementasikan sebagai kelas templat yang merangkum sebuah pointer dan menimpa operator pointer standar. Mereka memiliki sejumlah keunggulan dibandingkan pointer biasa. Mereka dijamin diinisialisasi sebagai null pointer atau pointer ke objek tumpukan. Peniruan melalui pointer nol diperiksa. Tidak perlu menghapus. Objek secara otomatis dibebaskan ketika pointer terakhir ke mereka telah pergi. Satu masalah signifikan dengan pointer cerdas ini adalah bahwa tidak seperti pointer biasa, mereka tidak menghormati warisan. Pointer pintar tidak menarik untuk kode polimorfik. Diberikan di bawah ini adalah contoh untuk penerapan smart pointer.
Contoh:
Kelas ini menerapkan pointer pintar ke objek tipe X. Objek itu sendiri terletak di heap. Berikut cara menggunakannya:
Seperti operator kelebihan beban lainnya, p akan berperilaku seperti pointer biasa,
sumber
http://en.wikipedia.org/wiki/Smart_pointer
sumber
Biarkan T menjadi kelas dalam tutorial ini. Petunjuk dalam C ++ dapat dibagi menjadi 3 jenis:
1) Petunjuk mentah :
Mereka memegang alamat memori ke lokasi di memori. Gunakan dengan hati-hati, karena program menjadi rumit sulit untuk dilacak.
Pointer dengan data atau alamat const {Baca mundur}
Pointer ke tipe data T yang merupakan const. Berarti Anda tidak dapat mengubah tipe data menggunakan pointer. yaitu
*ptr1 = 19
; tidak akan bekerja. Tapi Anda bisa memindahkan pointer. yaituptr1++ , ptr1--
; dll akan bekerja. Baca mundur: pointer ke tipe T yang merupakan constPointer const ke tipe data T. Berarti Anda tidak dapat memindahkan pointer tetapi Anda dapat mengubah nilai yang ditunjuk oleh pointer. yaitu
*ptr2 = 19
akan bekerja tetapiptr2++ ; ptr2--
dll tidak akan bekerja. Baca mundur: pointer pointer ke tipe TPointer const ke tipe data const T. Berarti Anda tidak bisa menggerakkan pointer juga tidak bisa mengubah pointer tipe data menjadi pointer. yaitu.
ptr3-- ; ptr3++ ; *ptr3 = 19;
tidak akan bekerja3) Smart Pointers : {
#include <memory>
}Pointer Bersama :
Diimplementasikan menggunakan penghitungan referensi untuk melacak berapa banyak "hal" menunjuk ke objek yang ditunjuk oleh pointer. Ketika jumlah ini masuk ke 0, objek dihapus secara otomatis, yaitu keberatan dihapus ketika semua share_ptr yang menunjuk ke objek keluar dari ruang lingkup. Ini menghilangkan sakit kepala karena harus menghapus objek yang telah Anda alokasikan menggunakan yang baru.
Weak Pointer: Membantu menangani referensi siklik yang muncul saat menggunakan Shared Pointer Jika Anda memiliki dua objek yang ditunjuk oleh dua pointer bersama dan ada internal pointer bersama menunjuk satu sama lain bersama pointer maka akan ada referensi siklik dan objek tidak akan dihapus ketika pointer bersama keluar dari ruang lingkup. Untuk mengatasi ini, ubah anggota internal dari shared_ptr menjadi kelemahan_ptr. Catatan: Untuk mengakses elemen yang ditunjuk oleh penunjuk lemah gunakan kunci (), ini mengembalikan melemah_ptr.
Lihat: Kapan std :: lemah_ptr berguna?
Pointer Unik: Pointer pintar ringan dengan kepemilikan eksklusif. Gunakan saat penunjuk menunjuk ke objek unik tanpa berbagi objek di antara pointer.
Untuk mengubah objek yang ditunjuk oleh ptr unik, gunakan pindahkan semantik
Referensi: Mereka pada dasarnya dapat dianggap sebagai const pointer, yaitu pointer yang merupakan const dan tidak dapat dipindahkan dengan sintaks yang lebih baik.
Lihat: Apa perbedaan antara variabel penunjuk dan variabel referensi dalam C ++?
Referensi: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Terima kasih kepada Andre yang telah menunjukkan pertanyaan ini.
sumber
Pointer pintar adalah kelas, pembungkus pointer normal. Tidak seperti pointer normal, lingkaran kehidupan titik pintar didasarkan pada jumlah referensi (berapa kali objek penunjuk pintar ditugaskan). Jadi, setiap kali pointer cerdas ditugaskan ke yang lain, referensi internal akan menghitung plus plus. Dan setiap kali objek keluar dari ruang lingkup, jumlah referensi dikurangi minus.
Pointer otomatis, meskipun terlihat serupa, sama sekali berbeda dari smart pointer. Ini adalah kelas yang mudah digunakan yang tidak menggunakan sumber daya kapan pun objek pointer otomatis keluar dari ruang lingkup variabel. Sampai batas tertentu, itu membuat pointer (ke memori yang dialokasikan secara dinamis) bekerja mirip dengan variabel stack (dialokasikan secara statis dalam waktu kompilasi).
sumber
Smart Pointer adalah di mana Anda tidak perlu khawatir tentang De-Alokasi Memori, Berbagi Sumber Daya, dan Transfer.
Anda dapat menggunakan pointer ini dengan sangat baik dengan cara yang sama seperti alokasi bekerja di Jawa. Di java Sampah Kolektor melakukan trik, sedangkan di Smart Pointers, trik tersebut dilakukan oleh Destructors.
sumber
Jawaban yang ada bagus tetapi tidak mencakup apa yang harus dilakukan ketika smart pointer bukan jawaban (lengkap) untuk masalah yang Anda coba selesaikan.
Antara lain (dijelaskan dengan baik dalam jawaban lain) menggunakan smart pointer adalah solusi yang memungkinkan untuk Bagaimana kita menggunakan kelas abstrak sebagai tipe fungsi kembali? yang telah ditandai sebagai duplikat dari pertanyaan ini. Namun, pertanyaan pertama yang ditanyakan apakah tergoda untuk menentukan kelas dasar abstrak (atau bahkan, ada) sebagai tipe pengembalian dalam C ++ adalah "apa maksudmu sebenarnya?". Ada diskusi yang baik (dengan referensi lebih lanjut) pemrograman berorientasi objek idiomatik dalam C ++ (dan bagaimana hal ini berbeda dengan bahasa lain) dalam dokumentasi perpustakaan penambah penunjuk arah. Singkatnya, di C ++ Anda harus memikirkan kepemilikan. Pointer pintar mana yang membantu Anda, tetapi bukan satu-satunya solusi, atau selalu merupakan solusi lengkap (mereka tidak memberi Anda salinan polimorfik) dan tidak selalu merupakan solusi yang ingin Anda paparkan di antarmuka Anda (dan pengembalian fungsi terdengar mengerikan. banyak seperti antarmuka). Mungkin cukup untuk mengembalikan referensi, misalnya. Tetapi dalam semua kasus ini (penunjuk pintar, penunjuk wadah atau hanya mengembalikan referensi) Anda telah mengubah pengembalian dari nilai ke beberapa bentuk referensi . Jika Anda benar-benar perlu menyalin, Anda mungkin perlu menambahkan "idiom" boilerplate atau beralih melampaui OO idiomatik (atau sebaliknya) di C ++ ke polimorfisme yang lebih umum menggunakan perpustakaan seperti Adobe Poly atau Boost.TypeErasure.
sumber