8

In cases where constructor dependency injection is required, what are the considerations for using injection by reference vs. using boost::shared_ptr?

Is there another common way of doing it? How does it compare to the two methods above?

Jonathan Livni
  • 101,334
  • 104
  • 266
  • 359
  • 2
    +1: I love dependency injection! – Nick Apr 20 '11 at 15:43
  • Using a pointer may help in certain scenarios. See following answer for such a case while testing the class: http://stackoverflow.com/questions/5726580/mocking-c-classes-with-dependency-injection/5836747#5836747 – Jonathan Livni May 01 '11 at 22:22

4 Answers4

5

It's your choice on how you want to manage the lifetime of the object you're injecting. The overall architecture will probably dictate which choice makes the most sense. With a reference, something at a higher level must manage the object lifetime; with shared_ptr the lifetime will be managed automatically.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
2

Previously I have used both methods.

The advantage of using the shared pointer approach means that you can pass ownership of the injected dependencies to the consumer.

If you use the reference based approach then destruction of the injected dependencies is much more deterministic. I.e. it occurs once all processing in the consumers has completed.

Nick
  • 25,026
  • 7
  • 51
  • 83
2

I remember seeing some code that did it with unique_ptr (or maybe auto_ptr). This seems to be better than "by reference": there is no need to manage the ownership of the injected object. This might be faster than using shared_ptr: no reference counting is involved. This might be more confusing though: it involves transfer of ownership, and auto_ptr has some pitfalls.

anatolyg
  • 26,506
  • 9
  • 60
  • 134
  • `unique_ptr` and `auto_ptr` don't give you the possibility of sharing the object. Again, whether this will be a problem depends on the overall architecture. – Mark Ransom Apr 20 '11 at 16:16
  • 1
    Its a good choice if the object owns (does not share) the injected object. – Martin York Apr 20 '11 at 17:43
-1

The question you need to ask yourself is: who owns the object? In a typical DI scenario, it is the consumer object. In that case, I would pass a raw pointer to the constructor and store it into something like unique_ptr. If the ownership is shared or not clear, than of course, use shared_ptr.

Nemanja Trifunovic
  • 24,346
  • 3
  • 50
  • 88
  • Huh? It should *never* be the consumer in DI - what if other objects need to use that instance as well? – BlueRaja - Danny Pflughoeft Apr 20 '11 at 16:31
  • @BlueRaja: Strictly speaking, it can be either way - DI is orthogonal to the aggregation vs. composition dilemma. – Nemanja Trifunovic Apr 20 '11 at 16:35
  • I would never pass a RAW pointer anywere. If nothing else wrapping a pointer in a smart pointer provides documentation (in the source) of what is supposed to happen to the object passing RAW p;pointers is just horrible and confusing. – Martin York Apr 20 '11 at 17:45
  • @Martin: What kind of smart pointer would you pass to a constructor of a container that is taking ownership of the dynamically allocated object? – Nemanja Trifunovic Apr 20 '11 at 17:56
  • I vote for thinking about ownership and scopes together when making decisions like this. – tp1 Apr 20 '11 at 18:01
  • @ Nemanja Trifunovic: boost::ptr_vector and other ptr containers that are designed to take ownership of pointers all accept std::auto_ptr to indicate the transfer of ownership to the container. If your container is not specifically designed to take ownership then of the pointer you should not be using it to hold pointers as it will not be exception safe. – Martin York Apr 20 '11 at 18:48
  • @Martin: The topic is about DI containers, not "collections". Passing a pointer to a constructor and assigning it via initializer list is guaranteed to be exception-safe. Sure, you can use std::auto_ptr instead, but there is no benefit of using that. Besides, auto_ptr is deprecated in C++11 – Nemanja Trifunovic Apr 20 '11 at 19:12
  • @Nemanja Trifunovic: You brought up containers not me (I was merly answering your comment). Sure auto_ptr is depreciated in the next standard, but you can use std::unique_ptr (the auto_ptr replacement) instead it does the same thing. – Martin York Apr 20 '11 at 19:55
  • @Martin: Yep, I meant consumer, not container (see my original answer). Anyway, I still don't see an advantage of using unique_ptr as an argument to a constructor of a DI consumer object. As I said, passing and assigning raw pointers are guaranteed to be exception-safe (no-exception guarantee, in fact). – Nemanja Trifunovic Apr 20 '11 at 20:15
  • @Nemanja Trifunovic: As I noted in my first comment it documents intent. Without it a maintainer does not know if you did it accidentally or on purpose. RAW pointers have now ownership semantics so it cant document intent. Smart pointers are not only safe but they document the intent of the developer. – Martin York Apr 20 '11 at 21:08