16

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:

  1. Impact on performance is negligible.
  2. It's safe, as Foobar controls lifetime od its Widget, so it makes sure that Widget doesn't suddenly disappear.
  3. It's safe that Widget won't leak and will be properly destructed when no longer needed.

However, this comes at a cost:

  1. It places restrictions on how Widget instances can be used, e.g. no stack-allocated Widgets can be used, no Widget 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:

  1. More universal, as it allows sharing dependencies.
  2. Maintains safety (points 2 and 3) of unique_ptr solution.

Disadvantages:

  1. Wastes resources when no sharing is involved.
  2. 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:

  1. As simple as it can get.
  2. Universal, accepts just any Widget.

Cons:

  1. Not safe anymore.
  2. Introduces another entity that is responsible for ownership of both Foobar and Widget.

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?

  • 1
    Right from the start, if you can compile under C++11 and/or never, having plain pointer as a way to handle resources in a class is not the recommended way anymore. If the Foobar class is the only owner of the resource and the resource should be freed, when Foobar goes out of scope, std::unique_ptr is the way to go. You can use std::move() to transfer the ownership of a resource from upper scope to the class. – Andy Sep 7 '15 at 21:18
  • 1
    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. – el.pescado Sep 8 '15 at 4:40
  • 1
    @el.pescado There is also the same problem in Java, memory isn't the only resource. There is also files and connections for example. The usual way to solve this in Java is to have a container that manages the lifecycle of all its contained objects. Therefore you don't have to worry about it in the objects contained in a DI container. This could also work for c++ applications if there is a way for the DI container to know when to switch to which lifecycle phase. – SpaceTrucker Sep 8 '15 at 6:41
  • 3
    Of course, you could do it the old-fashioned way without all the complexity and have code that works and is way easier to maintain. (Note that the Java boys may laugh, but they are always going on about refactoring, so decoupling isn't exactly helping them much) – gbjbaanb Sep 8 '15 at 7:39
  • 3
    Plus having other people laugh at you is not a reason for being like them. Listen to their arguments (other than "because we were told to") and implement DI if it brings tangible benefit to your project. In this case, think of the pattern as a very general rule, which you have to apply in a way that is specific to the project - all three approaches (and all other potential approaches which you haven't thought of yet) are valid given they bring an overall benefit (i.e. have more upsides than downsides). – user44761 Sep 8 '15 at 8:30
2

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.

2

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 Widgets 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 Sep 8 '15 at 7:24
  • For example, the problem I have with unique_ptr is unit testing (DI is advertised as testing-friendly): I want to test Foobar, so I create Widget, pass it to Foobar, exercise Foobar and then I want to inspect Widget, but unless Foobar somehow exposes it, I can't since it has been claimed by Foobar. – el.pescado Sep 8 '15 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 a Foobar method such as Widget* 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 the Widget class. – Andy Sep 8 '15 at 7:36
  • Good point, that makes sense. – el.pescado Sep 8 '15 at 8:03
  • 1
    If you converted a shared_ptr to a unique_ptr, how would you want to guarantee unique_ness??? – Aconcagua Sep 10 '15 at 1:11
0

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).

  • 1
    This precludes polymorphic behavior, which severely limits added value. – el.pescado Sep 8 '15 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 Sep 8 '15 at 12:36
1

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).

  • 1
    In C++, don't use classes 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 Sep 10 '15 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 Sep 10 '15 at 13:04
1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.