class Foobar
を使用する(依存する)クラスがあるとしWidget
ます。Widget
古き良き時代では、woludはのフィールドとして宣言されるFoobar
か、多態的な動作が必要な場合はスマートポインターとして宣言され、コンストラクタで初期化されます。
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)) {}
(…)
};
そして、私たちはすべて準備ができて完了です。残念ながら、今日は、Javaの子供たちはカップルとして、当然、彼らはそれを見たら、私たちを笑う、となりますFoobar
とWidget
一緒に。解決策は一見シンプルです。依存関係の注入を適用して、Foobar
クラスから依存関係を構築します。しかし、その後、C ++は依存関係の所有権について考えるように強制します。3つのソリューションが思い浮かびます。
ユニークなポインター
class Foobar {
std::unique_ptr<Widget> widget;
public:
Foobar(std::unique_ptr<Widget> &&w) : widget(w) {}
(…)
}
Foobar
それの唯一の所有権がWidget
それに渡されると主張する これには次の利点があります。
- パフォーマンスへの影響はごくわずかです。
Foobar
コントロールのライフタイムがWidget
であるため、安全です。そのため、Widget
突然消えることはありません。Widget
漏れることはなく、不要になったときに適切に破壊されます。
ただし、これにはコストがかかります。
Widget
インスタンスの使用方法に制限があります。たとえば、スタックに割り当てられたものWidgets
は使用Widget
できず、共有できません。
共有ポインター
class Foobar {
std::shared_ptr<Widget> widget;
public:
Foobar(const std::shared_ptr<Widget> &w) : widget(w) {}
(…)
}
これはおそらく、Javaおよびその他のガベージコレクション言語に最も近い同等のものです。利点:
- 依存関係を共有できるため、より普遍的です。
unique_ptr
ソリューションの安全性(ポイント2および3)を維持します。
短所:
- 共有が含まれていない場合、リソースを無駄にします。
- ヒープ割り当てが引き続き必要であり、スタック割り当てオブジェクトは許可されません。
昔ながらの観察ポインター
class Foobar {
Widget *widget;
public:
Foobar(Widget *w) : widget(w) {}
(…)
}
生のポインタをクラス内に配置し、所有権の負担を他の人に移します。長所:
- できるだけ簡単に。
- ユニバーサル、すべてを受け入れます
Widget
。
短所:
- もう安全ではありません。
- との両方の所有権を担当する別のエンティティを紹介
Foobar
しWidget
ます。
いくつかのクレイジーなテンプレートのメタプログラミング
私が考えることができる唯一の利点は、ソフトウェアが開発されている間に時間を見つけられなかった本をすべて読むことができるということです;)
3番目のソリューションは最も普遍的であり、何かを管理する必要Foobars
があるため、管理Widgets
は単純な変更です。ただし、生のポインターを使用すると気になりますが、一方で、スマートポインターソリューションは、依存関係のコンシューマーがその依存関係の作成方法を制限するので、私にとって違和感を覚えます。
何か不足していますか?それとも、C ++での依存性注入は簡単ではありませんか?クラスはその依存関係を所有するか、単にそれらを観察する必要がありますか?
Foobar
が唯一の所有者であることをどうやって知るのですか?古いケースでは簡単です。しかし、DIの問題は、私が見るように、クラスをその依存関係の構築から切り離し、またそれらの依存関係の所有権からも切り離します(所有権は構築に関連付けられているため)。Javaなどのガベージコレクション環境では、それは問題ではありません。C ++では、これはそうです。
std::unique_ptr
その方法を選択します。を使用std::move()
して、リソースの所有権を上位スコープからクラスに転送できます。