Apa itu smart pointer dan kapan saya harus menggunakannya?
Apa itu smart pointer dan kapan saya harus menggunakannya?
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
dan 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 (new MyObject());
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 goal
MyObject* ptr = new MyObject();
ptr->DoSomething(); // Use the object in some way
delete 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(new MyObject());
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_ptr
atau std::unique_ptr
.
void f()
{
{
std::unique_ptr<MyObject> ptr(new MyObject());
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_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
dan std::shared_ptr
.
void f()
{
typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
MyObjectPtr p1; // Empty
{
MyObjectPtr p2(new MyObject());
// 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 heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!
Kemungkinan lain adalah membuat referensi melingkar:
struct Owner {
std::shared_ptr<Owner> other;
};
std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
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_ptr
untuk mendefinisikan referensi lemah (tidak terhitung) ke a shared_ptr
.
std::auto_ptr<MyObject> p1 (new MyObject());
alih-alih std::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):
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 atau std::auto_ptr
kecuali dalam kasus khusus yang dapat Anda baca jika Anda harus.T*
adalah untuk std::unique_ptr<T>
apa std::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:
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
Dan auto_ptr
cukup 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:
Lihat juga:
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_ptr
sangat fleksibel dan berhubungan dengan berbagai macam skenario pembuangan, termasuk kasus di mana objek perlu "melewati batas DLL" (kasus mimpi buruk umum jika berbeda libc
digunakan 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 T
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 daripada shared_ptr
, tetapi membutuhkan jenis T
untuk menyediakan mekanisme penghitungan referensi sendiri.weak_ptr<T>
adalah penunjuk yang lemah, bekerja bersamaan dengan shared_ptr
untuk 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_ptr
untuk kepemilikan yang unik, std::shared_ptr
untuk kepemilikan bersama dan std::weak_ptr
. std::auto_ptr
ada di C ++ 03 tetapi sekarang sudah usang.
scoped_ptr
tidak seperti yang dideklarasikan secara lokal const 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:
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:
smart_pointer <employee> p= employee("Harris",1333);
Seperti operator kelebihan beban lainnya, p akan berperilaku seperti pointer biasa,
cout<<*p;
p->raise_salary(0.5);
http://en.wikipedia.org/wiki/Smart_pointer
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 = 19
akan 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 scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access
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.
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.
Lihat: Apa perbedaan antara variabel penunjuk dan variabel referensi dalam C ++?
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
Referensi: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Terima kasih kepada Andre yang telah menunjukkan pertanyaan ini.
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.