Ada banyak petunjuk dalam C ++ tetapi jujur dalam 5 tahun atau lebih dalam pemrograman C ++ (khusus dengan Qt Framework) Saya hanya menggunakan raw pointer lama:
SomeKindOfObject *someKindOfObject = new SomeKindOfObject();
Saya tahu ada banyak petunjuk "pintar" lainnya:
// shared pointer:
shared_ptr<SomeKindofObject> Object;
// unique pointer:
unique_ptr<SomeKindofObject> Object;
// weak pointer:
weak_ptr<SomeKindofObject> Object;
Tetapi saya tidak memiliki gagasan sedikit pun tentang apa yang harus dilakukan dengan mereka dan apa yang dapat mereka tawarkan kepada saya dibandingkan dengan petunjuk mentah.
Misalnya saya punya header kelas ini:
#ifndef LIBRARY
#define LIBRARY
class LIBRARY
{
public:
// Permanent list that will be updated from time to time where
// each items can be modified everywhere in the code:
QList<ItemThatWillBeUsedEveryWhere*> listOfUselessThings;
private:
// Temporary reader that will read something to put in the list
// and be quickly deleted:
QSettings *_reader;
// A dialog that will show something (just for the sake of example):
QDialog *_dialog;
};
#endif
Ini jelas tidak lengkap tetapi untuk masing-masing dari 3 petunjuk ini apakah boleh untuk membiarkan mereka "mentah" atau haruskah saya menggunakan sesuatu yang lebih tepat?
Dan di kedua kalinya, jika seorang majikan akan membaca kode, apakah dia akan ketat pada petunjuk apa yang saya gunakan atau tidak?
c++
programming-practices
pointers
qt
smart-pointer
CheshireChild
sumber
sumber
Jawaban:
Pointer "mentah" tidak dikelola. Yaitu, baris berikut:
... akan membocorkan memori jika pendamping
delete
tidak dilakukan pada waktu yang tepat.auto_ptr
Untuk meminimalkan kasus ini,
std::auto_ptr<>
diperkenalkan. Karena keterbatasan C ++ sebelum standar 2011, bagaimanapun, masih sangat mudah untukauto_ptr
membocorkan memori. Akan tetapi cukup untuk kasus terbatas, seperti ini:Salah satu kasus penggunaan terlemahnya adalah dalam wadah. Ini karena jika salinan yang
auto_ptr<>
dibuat dan salinan yang lama tidak diatur ulang dengan hati-hati, maka wadah dapat menghapus pointer dan kehilangan data.unique_ptr
Sebagai pengganti, C ++ 11 memperkenalkan
std::unique_ptr<>
:Seperti
unique_ptr<>
akan dibersihkan dengan benar, bahkan ketika itu melewati antara fungsi. Itu melakukan ini dengan secara semantik mewakili "kepemilikan" dari pointer - "pemilik" membersihkannya. Ini membuatnya ideal untuk digunakan dalam wadah:Berbeda dengan
auto_ptr<>
,unique_ptr<>
berperilaku baik di sini, dan ketikavector
mengubah ukuran, tidak ada objek yang akan terhapus secara tidak sengaja saatvector
salinannya menjadi backing store.shared_ptr
danweak_ptr
unique_ptr<>
tentu saja berguna, tetapi ada beberapa kasus di mana Anda ingin dua bagian basis kode Anda dapat merujuk ke objek yang sama dan menyalin pointer-nya, sambil tetap dijamin pembersihan yang benar. Misalnya, pohon mungkin terlihat seperti ini, ketika menggunakanstd::shared_ptr<>
:Dalam hal ini, kita bahkan dapat berpegang pada banyak salinan dari simpul root, dan pohon akan dibersihkan dengan benar ketika semua salinan dari simpul akar dihancurkan.
Ini berfungsi karena masing-masing
shared_ptr<>
memegang tidak hanya pointer ke objek, tetapi juga jumlah referensi dari semuashared_ptr<>
objek yang merujuk ke pointer yang sama. Saat yang baru dibuat, hitungannya naik. Ketika seseorang dihancurkan, hitungannya turun. Saat hitungan mencapai nol, penunjuknya adalahdelete
d.Jadi ini menimbulkan masalah: Struktur yang ditautkan ganda berakhir dengan referensi melingkar. Katakanlah kita ingin menambahkan
parent
pointer ke pohon kamiNode
:Sekarang, jika kita menghapus a
Node
, ada referensi siklik untuk itu. Itu tidak akan pernah menjadidelete
d karena jumlah referensi tidak akan pernah menjadi nol.Untuk mengatasi masalah ini, Anda menggunakan
std::weak_ptr<>
:Sekarang, semuanya akan berfungsi dengan benar, dan menghapus sebuah simpul tidak akan meninggalkan referensi yang macet ke simpul induk. Itu membuat berjalan pohon sedikit lebih rumit, namun:
Dengan cara ini, Anda dapat mengunci referensi ke simpul tersebut, dan Anda memiliki jaminan yang masuk akal bahwa simpul itu tidak akan hilang saat Anda mengerjakannya, karena Anda memegangnya
shared_ptr<>
.make_shared
danmake_unique
Sekarang, ada beberapa masalah kecil dengan
shared_ptr<>
danunique_ptr<>
yang harus diatasi. Dua baris berikut memiliki masalah:Jika
thrower()
melempar pengecualian, kedua saluran akan membocorkan memori. Dan lebih dari itu,shared_ptr<>
menahan jumlah referensi jauh dari objek yang ditunjuknya dan ini bisa berarti alokasi kedua). Itu biasanya tidak diinginkan.C ++ 11 menyediakan
std::make_shared<>()
dan C ++ 14 menyediakanstd::make_unique<>()
untuk memecahkan masalah ini:Sekarang, dalam kedua kasus, bahkan jika
thrower()
melempar pengecualian, tidak akan ada kebocoran memori. Sebagai bonus,make_shared<>()
memiliki kesempatan untuk membuat jumlah referensi dalam ruang memori yang sama dengan objek yang dikelola, yang keduanya dapat lebih cepat dan dapat menghemat beberapa byte memori, sambil memberikan Anda jaminan keamanan pengecualian!Catatan tentang Qt
Perlu dicatat, bahwa Qt, yang harus mendukung kompiler pra-C ++ 11, memiliki model pengumpulan sampah sendiri: Banyak
QObject
yang memiliki mekanisme di mana mereka akan dihancurkan dengan baik tanpa perlu pengguna untukdelete
itu.Saya tidak tahu bagaimana
QObject
s akan berperilaku ketika dikelola oleh pointer yang dikelola C ++ 11, jadi saya tidak bisa mengatakan itushared_ptr<QDialog>
adalah ide yang bagus. Saya tidak memiliki pengalaman yang cukup dengan Qt untuk mengatakan dengan pasti, tetapi saya percaya bahwa Qt5 telah disesuaikan untuk kasus penggunaan ini.sumber
shared_ptr
adalah objek yang terpisah - alokasi yang terpisah - darinew
objek ed. Mereka ada di lokasi yang berbeda.make_shared
memiliki kemampuan untuk menempatkan mereka bersama di lokasi yang sama, yang meningkatkan lokalitas cache, antara lain.shared_ptr
adalah sebuah objek. Dan untuk mengelola objek, ia harus mengalokasikan (referensi-hitungan (lemah + kuat) + perusak) -juga.make_shared
memungkinkan mengalokasikan itu dan objek yang dikelola sebagai satu bagian.unique_ptr
tidak menggunakan itu, jadi tidak ada keuntungan yang sesuai, selain memastikan objek selalu dimiliki oleh smart-pointer. Sebagai tambahan, seseorang dapat memilikishared_ptr
yang memiliki objek yang mendasarinya dan mewakilinullptr
, atau yang tidak memiliki dan mewakili non-nullpointer.shared_ptr
dilakukan oleh: . 2. Ini berisi pointer. Kedua bagian itu independen.make_unique
danmake_shared
keduanya memastikan objek yang dialokasikan dimasukkan dengan aman ke dalam smart-pointer. Selain itu,make_shared
memungkinkan mengalokasikan objek kepemilikan dan pointer dikelola bersama.