Diyelim ki sınıfı Foobarkullanan (bağlı) bir sınıfım var Widget. İyi günlerde, polimorfik davranış gerekiyorsa Widgetwolud bir alan olarak Foobarveya belki de akıllı bir işaretçi olarak ilan edilir ve yapıcıda başlatılır:
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)) {}
(…)
};
Ve hepimiz hazır olurduk. Ne yazık ki, bugün Java çocuklar gördükten sonra bize ve çiftler Foobarve Widgetbirlikte haklı olarak gülecekler . Çözüm basit görünüyor: Bağımlılıkların inşasını Foobarsınıftan çıkarmak için Bağımlılık Enjeksiyonu uygulayın . Ama sonra, C ++ bizi bağımlılıkların sahibi olmayı düşünmeye zorlar. Üç çözüm akla geliyor:
Benzersiz işaretçi
class Foobar {
std::unique_ptr<Widget> widget;
public:
Foobar(std::unique_ptr<Widget> &&w) : widget(w) {}
(…)
}
Foobarsadece mülkiyetin Widgetkendisine geçildiğini iddia ediyor . Bunun aşağıdaki avantajları vardır:
- Performans üzerindeki etkisi ihmal edilebilir düzeydedir.
FoobarKontroller ömür boyu güvenliWidgetolduğundan,Widgetaniden kaybolmadığından emin olur .WidgetSızıntı yapmayacak ve artık ihtiyaç duyulmadığında düzgün şekilde tahrip edilecek güvenlidir .
Ancak, bunun bir maliyeti vardır:
WidgetÖrneklerin nasıl kullanılabileceği konusunda kısıtlamalar getirir, örneğin yığın tahsisWidgetsedilemez,Widgetpaylaşılamaz.
Paylaşılan işaretçi
class Foobar {
std::shared_ptr<Widget> widget;
public:
Foobar(const std::shared_ptr<Widget> &w) : widget(w) {}
(…)
}
Bu muhtemelen Java ve çöp toplanan diğer dillere en yakın eşdeğerdir. Avantajları:
- Bağımlılık paylaşımına izin verdiği için daha evrensel.
unique_ptrÇözeltinin güvenliğini (madde 2 ve 3) korur .
Dezavantajları:
- Paylaşım olmadığında kaynakları israf eder.
- Yine de yığın ayırma gerektirir ve yığınla ayrılmış nesneleri devre dışı bırakır.
Düz ol 'gözlem işaretçisi
class Foobar {
Widget *widget;
public:
Foobar(Widget *w) : widget(w) {}
(…)
}
Ham işaretçiyi sınıfın içine yerleştirin ve sahip olma yükünü bir başkasına kaydırın. Artıları:
- Olabildiğince basit.
- Universal, sadece herhangi birini kabul eder
Widget.
Eksileri:
- Artık güvenli değil.
- Her ikisinin
Foobarve sahipliğinden sorumlu olan başka bir varlık tanıtırWidget.
Bazı çılgın şablon meta programlaması
Düşünebileceğim tek avantaj, yazılımım derlenirken zaman bulamadığım tüm kitapları okuyabileceğim;)
Üçüncü çözüme yaslanıyorum, en evrensel olduğu gibi, bir şey Foobarsyine de yönetmek zorunda , bu yüzden yönetmek Widgetsbasit bir değişiklik. Ancak, ham işaretçiler kullanmak beni rahatsız ediyor, diğer taraftan akıllı işaretçi çözümü bana yanlış geliyor, çünkü bağımlılık tüketicisini bu bağımlılığın nasıl yaratıldığını kısıtlıyorlar.
Bir şey mi kaçırıyorum? Yoksa sadece C ++ bağımlılık enjeksiyon önemsiz değil mi? Sınıf bağımlılıklarına mı sahip olmalı yoksa sadece gözlemlemeli mi?
Foobartek sahibi olduğunu nasıl bilebilirim ? Eski durumda basit. Ancak DI ile ilgili sorun, gördüğüm gibi, sınıfı bağımlılıklarının inşasından ayırdığı için, aynı zamanda bu bağımlılıkların sahipliğinden de ayrıştırmasıdır (sahiplik inşaata bağlı olduğu için). Java gibi çöp toplanmış ortamlarda bu bir sorun değildir. C ++ 'da, bu.
std::unique_ptrgidilecek yoldur.std::move()Bir kaynağın sahipliğini üst kapsamdan sınıfa aktarmak için kullanabilirsiniz .