Search code examples
c++boostdependency-injection

What is wrong with [boost.di] unique scope


I begin to use boost.di and I don't get about unique scope. Documentation says:

Scope representing unique/per request value. A new instance will be provided each time type will be requested.

#include <boost/di.hpp>
#include <assert.h>
namespace di = boost::di;

class server {
public:
};
int main()
{
    di::policies::constructible();
    di::injector<client> injector = di::make_injector(//<my_conf>
        di::bind<server>().in(di::unique)
    );
    std::shared_ptr<server> server1 = injector.create<std::shared_ptr<server>>();
    std::shared_ptr<server> server2 = injector.create<std::shared_ptr<server>>();
    assert(server1 != server2);
}

My assert failed! Why?


Solution

  • I trully believe you already found your answer for this, but I was studying this library and stumbled upon your question without answer here and thought it might be useful for others to find a written answer.

    So, the key poiny is the return type of di::make_injector.

    If you write like this snippet below you'll see the difference between asking for auto vs restricting it to injector.

      auto injector = di::make_injector(//<my_conf>
              di::bind<server>().in(di::unique)
          );
      std::cout << typeid(injector).name() << '\n';
    
      di::injector<client> injector2 = di::make_injector(//<my_conf>
              di::bind<server>().in(di::unique)
        );
      std::cout << typeid(injector2).name() << '\n';
    

    For reference, I put together a test code (written for testing with Catch2) which one can further explore the idea.

    #define CATCH_CONFIG_MAIN  
    #include <catch2/catch.hpp>
    
    #include <boost/di.hpp>
    
    namespace di = boost::di;
    
    
    struct server {
      virtual ~server() noexcept = default;
      // cannot be pure virtual because server has to be creatable to be called explicitly in
      // the injector call.
      virtual void dummy(){}; 
    };
    
    struct client : server {
      void dummy() override {}
    };
    
    
    TEST_CASE("injector","[Unique scope should return new objects at the same type creation call]")
    {
      di::policies::constructible();
      
      auto injector = di::make_injector(//<my_conf>
              di::bind<server>().to<client>().in(di::unique)
          );
    
      SECTION("new_objects"){
        std::shared_ptr<server> server1 = injector.create<std::shared_ptr<server>>();
        std::shared_ptr<server> server2 = injector.create<std::shared_ptr<server>>();
        CHECK((server1) != (server2));
    
        auto [server3, server4] = injector.create<std::tuple<std::shared_ptr<server>,std::shared_ptr<server>>>();
        CHECK(server3 != server4);
    
      }
    
      SECTION("in_constructor"){
        struct example {
          example(std::shared_ptr<server> sp1 /*unique*/
              , std::shared_ptr<server> sp2 /*unique*/
              ) {
            CHECK(sp1 != sp2);
          }
        };
    
        auto ex = injector.create<example>();
      }
    }
    
    

    I hope this helps somebody to use this good library.