Dependency injection in C++
Solution 1
This talk is about Java and dependency injection.
In C++ we try NOT to pass RAW pointers around. This is because a RAW pointer have no ownership semantics associated with it. If you have no ownership then we don't know who is responsible for cleaning up the object.
I find that most of the time dependency injection is done via references in C++.
In the rare cases where you must use pointers, wrap them in std::unique_ptr<> or std::shared_ptr<> depending on how you want to manage ownership.
In case you cannot use C++11 features, use std::auto_ptr<> or boost::shared_ptr<>.
I would also point out that C++ and Java styles of programming are now so divergent that applying the style of one language to the other will inevitably lead to disaster.
Solution 2
This is interesting, DI in C++ using templates:
http://adam.younglogic.com/?p=146
I think the author is making the right moves as to not translate Java DI into C++ too literally. Worth the read.
Solution 3
I've recently been bitten by the DI bug. I think it solves a lot of complexity problems, especially the automated part. I've written a prototype which lets you use DI in a pretty C++ way, or at least I think so. You can take a look at the code example here: http://codepad.org/GpOujZ79
The things that are obviously missing: no scoping, no binding of interface to implementation. The latter is pretty easy to solve, the former, I've no idea.
I'd be grateful if anyone here has an opinion on the code.
Solution 4
Use RAII.
Handing a raw pointer to someone is the same as handing them ownership. If that's not what you want to do, you should give them some kind of facade that also knows how to clean up the object in question.
shared_ptr<> can do this; the second argument of its constructor can be a function object that knows how to delete the object.
Solution 5
In C++, normally, when you done things right, you don't need to write destructors at all in most cases. You should use smart pointers to delete things automatically. I think, builder don't looks like the owner of the ClassA and ClassB instances. If you don't like to use smart pointers, you should think about objects life time and their owners.
Related videos on Youtube
eoleary
Curious Physicist that become a curious Software Engineer...
Updated on July 09, 2022Comments
-
eoleary 11 months
This is also a question that I asked in a comment in one of Miško Hevery's google talks that was dealing with dependency injection but it got buried in the comments.
I wonder how can the factory / builder step of wiring the dependencies together can work in C++.
I.e. we have a class A that depends on B. The builder will allocate B in the heap, pass a pointer to B in A's constructor while also allocating in the heap and return a pointer to A.
Who cleans up afterwards? Is it good to let the builder clean up after it's done? It seems to be the correct method since in the talk it says that the builder should setup objects that are expected to have the same lifetime or at least the dependencies have longer lifetime (I also have a question on that). What I mean in code:
class builder { public: builder() : m_ClassA(NULL),m_ClassB(NULL) { } ~builder() { if (m_ClassB) { delete m_ClassB; } if (m_ClassA) { delete m_ClassA; } } ClassA *build() { m_ClassB = new class B; m_ClassA = new class A(m_ClassB); return m_ClassA; } };Now if there is a dependency that is expected to last longer than the lifetime of the object we are injecting it into (say ClassC is that dependency) I understand that we should change the build method to something like:
ClassA *builder::build(ClassC *classC) { m_ClassB = new class B; m_ClassA = new class A(m_ClassB, classC); return m_ClassA; }What is your preferred approach?
-
Martin York over 14 yearsPS you do not need to test for NULL before a delete. -
Martin York over 14 yearsNB try and delete in the reverse order of creation. -
lmat - Reinstate Monica over 9 yearsI know nothing about this problem space, but what occurs to me first is that the framework should own (and clean up) anything it creates or gets from factories, right ? What am I missing ? Maybe I'm getting stick in the Spring Singleton pattern ?
-
-
phtrivier over 13 yearsMartin, does this mean that you inject all dependencies as references, and you copy them inside the dependent object ?
-
Martin York over 13 years@phtriver: No. It all depends on the situation. But usually we pass a reference and then inside the object we maintain that reference. -
daramarak over 13 yearsUsually, when I encounter situations like your A and B example. The ownership of both A and B belongs to a higher level class, usually the creator of the A classes. In my experience there is almost always a single owner, and that is the way to avoid shared_ptr. Reimplementing a shared_ptr for yourself (ref counting) sounds like a breach of the DRY principle (do not repeat yourself), and as with all repetitions is increases the prob. of a bug occuring.
-
Sohail about 13 yearsI've posted the code on bitbucket now: bitbucket.org/cheez/dicpp - I still have to do provider injection but I think that is easily done. Scoping is also implemented.
-
NoSenseEtAl over 10 yearsbreaking news 4 y after the answer: ): since couple of years ago auto_ptr is declared abomination. :D But now std has shared_ptr
-
MFH almost 8 yearsbreaking news 3 years later: auto_ptr was replaced by unique_ptr 4 years ago :D