Say I have a class Foobar that uses (depends on) class Widget. In good ol' days, Widget wolud be declared as a field in Foobar, or maybe as a smart pointer if polymorphic behavior was needed, and it would be initialized in constructor:
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)) {}
(…)
};
And we'd be all set and done. Unfortunately, today, Java kids will laugh at us once they see it, and rightfully, as it couples Foobar and Widget together. The solution is seemingly simple: apply Dependency Injection to take construction of dependencies out of Foobar class. But then, C++ forces us to think about ownership of dependencies. Three solutions come to mind:
Unique pointer
class Foobar {
std::unique_ptr<Widget> widget;
public:
Foobar(std::unique_ptr<Widget> &&w) : widget(w) {}
(…)
}
Foobar claims sole ownership of Widget that is passed to it. This has following advantages:
- Impact on performance is negligible.
- It's safe, as
Foobarcontrols lifetime od itsWidget, so it makes sure thatWidgetdoesn't suddenly disappear. - It's safe that
Widgetwon't leak and will be properly destructed when no longer needed.
However, this comes at a cost:
- It places restrictions on how
Widgetinstances can be used, e.g. no stack-allocatedWidgetscan be used, noWidgetcan be shared.
Shared pointer
class Foobar {
std::shared_ptr<Widget> widget;
public:
Foobar(const std::shared_ptr<Widget> &w) : widget(w) {}
(…)
}
This is probably closest equivalent ot Java and other garbage collected languages. Advantages:
- More universal, as it allows sharing dependencies.
- Maintains safety (points 2 and 3) of
unique_ptrsolution.
Disadvantages:
- Wastes resources when no sharing is involved.
- Still requires heap allocation and disallows stack-allocated objects.
Plain ol' observing pointer
class Foobar {
Widget *widget;
public:
Foobar(Widget *w) : widget(w) {}
(…)
}
Place raw pointer inside class and shift the burden of ownership to someone else. Pros:
- As simple as it can get.
- Universal, accepts just any
Widget.
Cons:
- Not safe anymore.
- Introduces another entity that is responsible for ownership of both
FoobarandWidget.
Some crazy template metaprogramming
The only advantage I can think of is that I'd be able to read all those books I didn't find time for while my software is builing;)
I lean towards the third solution, as it is most universal, something has to manage Foobars anyway, so managing Widgets is simple change. However, using raw pointers bothers me, on the other hand smart pointer solution feel wrong to me, as they make consumer of dependency restrict how that dependency is created.
Am I missing something? Or is just Dependency Injection in C++ not trivial? Should class own its dependencies or just observe them?
std::unique_ptris the way to go. You can usestd::move()to transfer the ownership of a resource from upper scope to the class.Foobaris the only owner? In the old case it's simple. But the problem with DI, as I see it, is as it decouples class from construction of its dependencies, it also decouples it from ownership of those dependencies (as ownership is tied to construction). In garbage collected environments such as Java, that's not a problem. In C++, this is.