Katakanlah saya memiliki kelas Foobaryang menggunakan (tergantung pada) kelas Widget. Pada hari-hari baik, Widgetwolud dinyatakan sebagai bidang Foobar, atau mungkin sebagai penunjuk pintar jika perilaku polimorfik diperlukan, dan itu akan diinisialisasi dalam konstruktor:
class Foobar {
Widget widget;
public:
Foobar() : widget(blah blah blah) {}
// or
std::unique_ptr<Widget> widget;
public:
Foobar() : widget(std::make_unique<Widget>(blah blah blah)) {}
(…)
};
Dan kita akan siap dan selesai. Sayangnya, hari ini, anak-anak Jawa akan menertawakan kita begitu mereka melihatnya, dan memang seharusnya, karena pasangan Foobardan Widgetbersama - sama. Solusinya tampaknya sederhana: gunakan Injeksi Ketergantungan untuk mengambil konstruksi dependensi di luar Foobarkelas. Tapi kemudian, C ++ memaksa kita untuk berpikir tentang kepemilikan dependensi. Tiga solusi muncul dalam pikiran:
Pointer unik
class Foobar {
std::unique_ptr<Widget> widget;
public:
Foobar(std::unique_ptr<Widget> &&w) : widget(w) {}
(…)
}
Foobarmengklaim kepemilikan satu-satunya Widgetyang diberikan padanya. Ini memiliki keuntungan sebagai berikut:
- Dampak pada kinerja dapat diabaikan.
- Ini aman, karena
Foobarmengontrol masa pakaiWidget, jadi itu memastikan bahwaWidgettidak tiba-tiba menghilang. - Aman
Widgettidak akan bocor dan akan dihancurkan dengan benar ketika tidak lagi dibutuhkan.
Namun, ini harus dibayar:
- Ini menempatkan pembatasan pada bagaimana
Widgetinstance dapat digunakan, misalnya tidak ada stack-dialokasikanWidgetsdapat digunakan, tidakWidgetdapat dibagikan.
Pointer yang dibagikan
class Foobar {
std::shared_ptr<Widget> widget;
public:
Foobar(const std::shared_ptr<Widget> &w) : widget(w) {}
(…)
}
Ini mungkin setara atau paling dekat dengan Jawa dan bahasa pengumpulan sampah lainnya. Keuntungan:
- Lebih universal, karena memungkinkan berbagi dependensi.
- Menjaga keamanan (poin 2 dan 3) dari
unique_ptrsolusi.
Kekurangan:
- Menghabiskan sumber daya saat tidak ada pembagian yang terlibat.
- Masih membutuhkan alokasi tumpukan dan melarang objek yang dialokasikan tumpukan.
Pointer pengamatan biasa
class Foobar {
Widget *widget;
public:
Foobar(Widget *w) : widget(w) {}
(…)
}
Tempatkan pointer mentah di dalam kelas dan mengalihkan beban kepemilikan kepada orang lain. Pro:
- Sesederhana itu bisa.
- Universal, menerima sembarang saja
Widget.
Cons:
- Tidak aman lagi.
- Memperkenalkan entitas lain yang bertanggung jawab atas kepemilikan keduanya
FoobardanWidget.
Beberapa metaprogram template gila
Satu-satunya keuntungan yang dapat saya pikirkan adalah bahwa saya dapat membaca semua buku yang saya tidak punya waktu untuk sementara perangkat lunak saya builing;)
Saya condong ke solusi ketiga, karena paling universal, Foobarsbagaimanapun juga, ada sesuatu yang harus dikelola , jadi mengelola Widgetsadalah perubahan sederhana. Namun, menggunakan raw pointer mengganggu saya, di sisi lain solusi smart pointer merasa salah bagi saya, karena mereka membuat konsumen ketergantungan membatasi bagaimana ketergantungan itu dibuat.
Apakah saya melewatkan sesuatu? Atau apakah Injeksi Ketergantungan pada C ++ tidak sepele? Haruskah kelas memiliki dependensi atau hanya mengamati mereka?
Foobarsatu-satunya pemilik? Dalam kasus lama itu sederhana. Tetapi masalah dengan DI, seperti yang saya lihat, adalah karena ia memisahkan kelas dari konstruksi dependensinya, ia juga memisahkannya dari kepemilikan dependensi tersebut (karena kepemilikan terkait dengan konstruksi). Di lingkungan sampah yang dikumpulkan seperti Jawa, itu tidak masalah. Di C ++, ini.
std::unique_ptradalah cara untuk pergi. Anda dapat menggunakanstd::move()untuk mentransfer kepemilikan sumber daya dari ruang lingkup atas ke kelas.