boost-ext / di

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

Shared scope behaves unexpectedly when the injector is a class member #527

Open Chaoses-Ib opened 2 years ago

Chaoses-Ib commented 2 years ago

Expected Behavior

When the object where the injector resides is destroyed, the objects created in shared scope by the injector should also be destroyed.

Actual Behavior

Objects in shared scope are not destroyed on destructuring, but only at the end of the process.

Steps to Reproduce the Problem

#include <iostream>
using std::cout;

#include <boost/di.hpp>
#include <boost/di/extension/scopes/shared.hpp>
namespace di = boost::di;

#define CLASS_PRINT(name) \
    name(const name&) { cout << #name " copy\n"; } \
    name(const name&&) { cout << #name " move\n"; } \
    name& operator=(const name&) { cout << #name " operator=\n"; } \
    name& operator=(const name&&) { cout << #name " operator= move\n"; } \
    ~name() { cout << #name " dtor\n"; }

class A {
public:
    A() {
        cout << "A ctor\n";
    }
    CLASS_PRINT(A)
};

class B {
public:
    B(A& a) {
        cout << "B ctor\n";
    }
    CLASS_PRINT(B)
};

class C {
public:
    C(A& a, B b) {
        cout << "C ctor\n";
    }
    CLASS_PRINT(C)
};

class Class1 {
    di::injector<di::extension::shared_config> injector;
public:
    Class1() : injector(di::make_injector<di::extension::shared_config>()) {
        cout << "Class1(){\n";

        C c = injector.create<C>();
        cout << "Class1: C created\n";

        cout << "}\n\n";
    }

    ~Class1() {
        cout << "Class1: ~Class1(){\n";

        cout << "//Why A is not destructured here?\n";
    }
};

void func1(){
    cout << "func1(){\n";

    auto injector = di::make_injector<di::extension::shared_config>();

    C c = injector.create<C>();
    cout << "func1: C created\n";

    cout << "}\n\n";

    cout << "{\n";
}

int main()
{
    func1();
    cout << "}\n\n";

    {
        Class1 c1;
    }
    cout << "}\n\n";

    cout << "//The end of main\n";
}

Output:

func1(){
A ctor
B ctor
B move
B dtor
C ctor
B dtor
C move
C dtor
func1: C created
}

{
C dtor
A dtor
}

Class1(){
A ctor
B ctor
B move
B dtor
C ctor
B dtor
C move
C dtor
Class1: C created
}

C dtor
Class1: ~Class1(){
//Why A is not destructured here?
}

//The end of main
A dtor

Specifications

Chaoses-Ib commented 2 years ago

di::make_injector(di::bind<A>().in(di::extension::shared)) has the same result.

Chaoses-Ib commented 1 year ago

After a year, I found a solution: change

class Class1 {
    di::injector<di::extension::shared_config> injector;
public:
    Class1() : injector(di::make_injector<di::extension::shared_config>());
};

to

class Class1 {
    di::core::injector<di::extension::shared_config, di::core::pool_t<>> injector;
public:
    Class1() : injector(di::make_injector<di::extension::shared_config>());
};