I am going back to C++ after spending some time in memory-managed languages, and I\'m suddently kinda lost as to what is the best way to implement dependency injection. (I a
[update 1]
If you can always guarantee the dependency outlives the addict, you can use a raw pointer/reference, of course. between these two, I'd make a very simple decision: pointer if NULL is allowed, reference otherwise.
(The point of my original post was that neither pointer nor reference solve the lifetime problem)
I'd follow the infamous google style guideline here, and use smart pointers.
Both a pointer and a reference have the same problem: you need to make sure the dependency outlives the addict. That pushes a quite nasty responsibility onto the client.
With a (reference-counted) smart pointer, the policy becomes dependency is destroyed when noone uses it anymore. Sounds perfect to me.
Even better: with boost::shared_ptr
(or a similar smart pointer that allows a type-neutral destruction policy) the policy is attached to the object at construction - which usually means everything affecting the dependency ends up in a single place.
The typical problems of smart pointers - overhead and circular references - rarely come into play here. Dependency instances usually aren't tiny and numerous, and a dependency that has a strong reference back to its addicts is at least a code smell. (still, you need to keep these things in mind. Welcome back to C++)
Warning: I am not "totally sold" to DI, but I'm totally sold on smart pointers ;)
[update 2]
Note that you can always create a shared_ptr
to a stack/global instance using a null deleter.
This requires both sides to support this, though: addict must make guarantees that it will not transfer a reference to the dependency to someone else who might live longer, and caller is back with the responsibility ensuring lifetime. I am not to happy with this solution, but have used this on occasion.
But then I get other, equally authoritive advices against using references as member : http://billharlan.com/pub/papers/Managing%5FCpp%5FObjects.html
In this case I think you only want to set the object once, in the constructor, and never change it so no problem. But if you want to change it later on, use an init function, have a copy constructor, in short everything that would have to change the reference you will have to use pointers.
I can here my downmoderation coming already, but I will say that there should be no reference members in a class FOR ANY REASO, EVER. Except if they are a simple constant value. The reasons for this are many, the second you start this you open up all the bad things in C++. See my blog if you really care.
There is no hard and fast rule:
As people have mentioned using references inside objects can cause copy problems (and it does) so it is not a panacea, but for certain situation it can be useful (that is why C++ gives us the option to do it all these different ways). But using RAW pointers is really not an option. If you are dynamically allocating objects then you should always be maintaining them with smart pointers and your object should also be using smart pointers.
For people who demand examples: Streams are always passed and stored as references (as they can't be copied).
Some Comments on your code examples:
Your first example with pointers. Is basically the same as the second example using references. The difference being that a reference can not be NULL. When you pass a reference the object is already alive and thus should have a lifespan greater than the object you are testing already (If it was created on the stack) so it should be safe to keep a reference. If you are dynamically creating pointers as dependencies I would consider using boost::shared_pointer or std::auto_ptr depending if ownership of the dependency is shared or not.
I don't see any great use for your third example. This is because you can not use polymorphic types (If you pass an object derived from Dependency it will be sliced during the copy operation). Thus the code may as well be inside Addict rather than a separate class.
Not to take anything away from Bill But:
class Lexer
{
public: Lexer(std::istream& input,std::ostream& errors);
... STUFF
private:
std::istream& m_input;
std::ostream& m_errors;
};
class Parser
{
public: Parser(Lexer& lexer);
..... STUFF
private:
Lexer& m_lexer;
};
int main()
{
CLexer lexer(std::cin,std::cout); // CLexer derived from Lexer
CParser parser(lexer); // CParser derived from Parser
parser.parse();
}
// In test.cpp
int main()
{
std::stringstream testData("XXXXXX");
std::stringstream output;
XLexer lexer(testData,output);
XParser parser(lexer);
parser.parse();
}
It has been asked before, but my SO search skills are not up to finding it. To summarise my position - you should very rarely, if ever, use references as class members. Doing so causes all sorts of initialisation, assignment and copying problems. Instead, use a pointer or a value.
Edit: Found one - this is a question with a variety of opinions as answers: Should I prefer pointers or references in member data?
Summary: If you need to store a reference, store a pointer as a private variable and access it through a method which dereferences it. You can stick a check that the pointer isn't null in the object's invariant.
In depth:
Firstly, storing references in classes makes it impossible to implement a sensible and legal copy constructor or assignment operator, so they should be avoided. It is usually a mistake to use one.
Secondly, the type of pointer/reference passed in to functions and constructors should indicate who has responsibility for freeing the object and how it should be freed:
std::auto_ptr - the called function is responsible for freeing, and will do so automatically when it's done. If you need copy semantics, the interface must provide a clone method which should return an auto_ptr.
std::shared_ptr - the called function is responsible for freeing, and will do so automatically when it's done and when all other references to the object are gone. If you need shallow copy semantics the compiler generated functions will be fine, if you need deep copying the interface must provide a clone method which should return a shared_ptr.
A reference - the caller has responsibility. You don't care - the object may be stack allocated for all you know. In this case you should pass by reference but store by pointer. If you need shallow copy semantics the compiler generated functions will be fine, if you need deep copying you're in trouble.
A raw pointer. Who knows? Could be allocated anywhere. Could be null. You might be responsible for freeing it, you might not.
Any other smart pointer - it should manage the lifetime for you, but you'll need to look at the documentation to see what the requirements are for copying.
Note that the methods which give you responsibility for freeing the object don't break DI - freeing the object is simply a part of the contract you have with the interface (as you don't need to know anything about the concrete type to free it).