boost-ext / di

C++14 Dependency Injection Library
https://boost-ext.github.io/di
1.16k stars 140 forks source link

How to use boost::di as a DI container? #383

Closed Dragnalith closed 5 years ago

Dragnalith commented 5 years ago

I was expected boost::di to work the same as other dependency container I have seen like Ninject (C#) or Kangaru (C++). In other word I would have expected two different injector instances holding two different singleton instances. But it seems it is not the case, for instance the last assert of the snippet below fails.

Is is the intended behavior? Is there a way to use boost::di as a service container?

#include <boost/di.hpp>
class MyClass_0_0 {
};
#include <assert.h>

int main()
{
    auto injector = boost::di::make_injector(boost::di::bind<MyClass_0_0>().in(boost::di::singleton));

    MyClass_0_0* instance1 = &injector.create<MyClass_0_0&>();
    MyClass_0_0* instance2 = &injector.create<MyClass_0_0&>();

    assert(instance1 == instance2);

    auto injector2 = boost::di::make_injector(boost::di::bind<MyClass_0_0>().in(boost::di::singleton));

    MyClass_0_0* instance3 = &injector2.create<MyClass_0_0&>();
    MyClass_0_0* instance4 = &injector2.create<MyClass_0_0&>();

    assert(instance3 == instance4);

    assert(instance1 != instance4); // Fails!

    return 0;
}
krzysztof-jusiak commented 5 years ago

@Dragnalith, [Boost].DI by default is using singleton scope for shared dependencies (&, shared_ptr, etc.) which the lifetime is same as the lifetime of the app. However, there is a shared scope which lifetime is same as the lifetime of the injector -> http://boost-experimental.github.io/di/extensions/index.html#shared-scope. I guess that's the one you are after?

boost::di::bind<MyClass_0_0>().in(boost::di::extension::shared)
kanstantsin-chernik commented 5 years ago

@krzysztof-jusiak, I think it worth adding explicit warning somewhere in the docs with explanation why it happens and how to avoid it if necessary.

Toinouze commented 5 years ago

@krzysztof-jusiak I had a similar issue and I also struggled to understand how it works behind the scenes. in(boost::di::extension::shared) To me this line means "make these injectors share their scope". I agree with @Dragnalith : by default, injectors should be self-contained and not magically share scopes behind the scenes. After all, one of the main benefit of DI is to avoid magic bindings and global state between systems that have no visible shared dependencies.

I think the "shared scope" extension should, well, make injectors share their scope.