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
Foobar
controls lifetime od itsWidget
, so it makes sure thatWidget
doesn't suddenly disappear. - It's safe that
Widget
won't leak and will be properly destructed when no longer needed.
However, this comes at a cost:
- It places restrictions on how
Widget
instances can be used, e.g. no stack-allocatedWidgets
can be used, noWidget
can 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_ptr
solution.
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
Foobar
andWidget
.
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?
5 Answers 5
I meant to write this as a comment, but it turned out to be too long.
How I know that
Foobar
is 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.
Whether you should use std::unique_ptr<Widget>
or std::shared_ptr<Widget>
, that is up to you to decide and comes from your functionality.
Let's assume you have a Utilities::Factory
, which is responsible for the creation of your blocks, such as Foobar
. Following the DI principle, you will need the Widget
instance, to inject it using Foobar
's constructor, meaning inside one of the Utilities::Factory
's method, for example createWidget(const std::vector<std::string>& params)
, you create the Widget and inject it into the Foobar
object.
Now you have a Utilities::Factory
method, which created the Widget
object. Does it mean, the method should me responsible for its deletion? Of course not. It is only there to make you the instance.
Let's imagine, you are developing an application, which will have multiple windows. Each window is represented using the Foobar
class, so in fact the Foobar
acts like a controller.
The controller will probably make use of some of your Widget
s and you have to ask yourself:
If I go on this specific window in my application, I will need these Widgets. Are these widgets shared among other application windows? If so, I shouldn't be probably creating them all over again, because they will always look the same, because they are shared.
std::shared_ptr<Widget>
is the way to go.
You also have an application window, where there is a Widget
specifically tied to this one window only, meaning it won't be displayed anywhere else. So if you close the window, you don't need the Widget
anywhere in your application anymore, or at least its instance.
That's where std::unique_ptr<Widget>
comes to claim its throne.
Update:
I don't really agree with @DominicMcDonnell, about the lifetime issue. Calling std::move
on std::unique_ptr
completely transfers the ownership, so even if you create an object A
in a method and pass it to another object B
as a dependency, the object B
will now be responsible for the resource of object A
and will correctly delete it, when object B
goes out of scope.
-
The general idea of ownership and smart pointers is clear to me. It just doesn't seem to me to play nice with the idea of DI. Dependency Injection is, to me, about decoupling class from its dependencies, yet in this case class still influences how its dependencies are created.el.pescado - нет войне– el.pescado - нет войне09/08/2015 07:24:10Commented Sep 8, 2015 at 7:24
-
1For example, the problem I have with
unique_ptr
is unit testing (DI is advertised as testing-friendly): I want to testFoobar
, so I createWidget
, pass it toFoobar
, exerciseFoobar
and then I want to inspectWidget
, but unlessFoobar
somehow exposes it, I can't since it has been claimed byFoobar
.el.pescado - нет войне– el.pescado - нет войне09/08/2015 07:33:24Commented Sep 8, 2015 at 7:33 -
@el.pescado You are mixing two things together. You are mixing accessibility and ownership. Just because
Foobar
owns the resource does not mean, nobody else should use it. You could implement aFoobar
method such asWidget* getWidget() const { return this->_widget.get(); }
, which will return you the raw pointer you can work with. You can then use this method as an input for your unit tests, when you want to test theWidget
class.Andy– Andy09/08/2015 07:36:42Commented Sep 8, 2015 at 7:36 -
Good point, that makes sense.el.pescado - нет войне– el.pescado - нет войне09/08/2015 08:03:29Commented Sep 8, 2015 at 8:03
-
1If you converted a shared_ptr to a unique_ptr, how would you want to guarantee unique_ness???Aconcagua– Aconcagua09/10/2015 01:11:16Commented Sep 10, 2015 at 1:11
I would use an observing pointer in the form of a reference. It gives a much better syntax when you use it and the has the semantic advantage that it doesn't imply ownership, which a plain pointer can.
The biggest problem with this approach is lifetimes. You have to ensure that the dependency is constructed before, and destructed after your depending class. It isn't a simple problem. Using shared pointers (as dependency storage and in all classes that depend on it, option 2 above) can remove this problem, but also introduces the problem of circular dependencies which is also non-trivial, and in my opinion less obvious and therefore harder to detect before it causes problems. Which is why I prefer to not do it automatically and manually manage the lifetimes and construction order. I've also seen systems that use a light template approach which constructed a list of objects in the order they were created and destroyed them in opposite order, it wasn't foolproof, but it made things a lot simpler.
Update
David Packer's response made me think a little more about the question. The original answer is true for shared dependencies in my experience, which is one of the advantages of dependency injection, you can have multiple instances using the one instance of a dependency. If however your class needs to have it's own instance of a particular dependency then std::unique_ptr
is the correct answer.
You ignored a fourth possible answer, which combines the first code you posted (the "good ol' days" of storing a member by value) with dependency injection:
class Foobar {
Widget widget;
public:
Foobar(Widget w) // pass w by value
: widget{ std::move(w) } {}
};
Client code can then write:
Widget w;
Foobar f1{ w }; // default: copy w into f1
Foobar f2{ std::move(w) }; // move w into f2
Representing the coupling between objects should not be done (purely) on the criteria you listed (that is, not based purely on "which is better for safe lifetime management").
You can also use conceptual criteria ("a car has four wheels" vs. "a car uses four wheels which the driver has to bring along").
You can have criteria imposed by other APIs (if what you get from an API is a custom wrapper or a std::unique_ptr for example, the options in your client code are limited as well).
-
2This precludes polymorphic behavior, which severely limits added value.el.pescado - нет войне– el.pescado - нет войне09/08/2015 11:57:28Commented Sep 8, 2015 at 11:57
-
True. I just thought to mention it since it is the form I end up using the most (I only use inheritance in my coding for polymorphic behavior - not code reuse, so I don't have many cases of needing polymorphic behavior)..utnapistim– utnapistim09/08/2015 12:36:28Commented Sep 8, 2015 at 12:36
First of all - this is C++, not Java - and here many things go differently. The Java people do not have those problems about ownership as there is automatic garbage collection that solves those for them.
Second: There is no general answer to this question - it depends on what the requirements are!
What is the problem about coupling FooBar and Widget? FooBar wants to use a Widget, and if every FooBar instance always will have its own and the same Widget anyway, leave it coupled...
In C++, you can even do "weird" things that simply do not exist in Java, e. g. have a variadic template constructor (well, there exists a ... notation in Java, which can be used in constructors, too, but that is just syntactic sugar to hide an object array, which actually has nothing to do with real variadic templates!) - category 'Some crazy template metaprogramming':
namespace WidgetFactory
{
Widget* create(int, int)
{
return 0;
}
Widget* create(int, bool, long)
{
return 0;
}
}
class FooBar
{
public:
template < typename ...Arguments >
FooBar(Arguments... arguments)
: mWidget(WidgetFactory::create(arguments...))
{
}
~FooBar()
{
delete mWidget;
}
private:
Widget* mWidget;
};
FooBar foobar1(10, 12);
FooBar foobar2(51, true, 54L);
Like it?
Of course, there are reasons when you want or need to decouple both classes - e. g. if you need to create the widgets at a time far before any FooBar instance exists, if you want or need to reuse the widgets, ..., or simply because for the current problem it is more appropriate (e. g. if Widget is a GUI element and FooBar shall/can/must not be one).
Then, we get back to the second point: No general answer. You need to decide, what - for the actual problem - is the more appropriate solution. I like DominicMcDonnell's reference approach, but it can only be applied if ownership shall not be taken by FooBar (well, actually, you could, but that implies very, very dirty code...). Apart from that, I join David Packer's answer (the one meant to be written as comment - but a good answer, anyway).
-
1In C++, don't use
class
es with nothing but static methods, even if it's just a factory as in your example. That violates the OO principles. Use namespaces instead and group your functions using them.Andy– Andy09/10/2015 12:57:10Commented Sep 10, 2015 at 12:57 -
@DavidPacker Hmm, sure, you're right - I silently assumed the class to have some private internals, but that's neither visible nor mentioned elsewhere...Aconcagua– Aconcagua09/10/2015 13:04:01Commented Sep 10, 2015 at 13:04
You are missing at least two more options that are available to you in C++:
One is to use 'static' dependency injection where your dependencies are template parameters. This gives you the option of holding your dependencies by value while still allowing compile time dependency injection. STL containers use this approach for allocators and comparison and hash functions for example.
Another is to take polymorphic objects by value using a deep copy. The traditional way to do this is using a virtual clone method, another option that's become popular is to use type erasure to make value types that behave polymorphically.
Which option is most appropriate really depends on your use case, it's hard to give a general answer. If you only need static polymorphism though I'd say templates are the most C++ way to go.
Explore related questions
See similar questions with these tags.
std::unique_ptr
is the way to go. You can usestd::move()
to transfer the ownership of a resource from upper scope to the class.Foobar
is 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.