Reputation: 1187
Taking this sample code I'd like to have as a result that button1 and button2 are two separate ojects.
#include <iostream>
#include <memory>
#include "di.hpp"
namespace di = boost::di;
struct CommandQueue {
void addCommand() {}
};
struct Control {
Control( CommandQueue &cq ) : cq( cq ) {
static int sid{};
id = ++sid;
}
CommandQueue& cq;
int id{};
};
int main() {
auto injector = di::make_injector( di::bind<CommandQueue>().in(di::singleton) );
auto button1 = injector.create<std::shared_ptr<Control>>();
auto button2 = injector.create<std::shared_ptr<Control>>();
std::cout << "button1->id = " << button1->id << std::endl;
std::cout << "button2->id = " << button2->id << std::endl;
return 0;
}
The current output is:
button1->id = 1
button2->id = 1
Instead of the intended:
button1->id = 1
button2->id = 2
Removing the di::singleton
lifetime scope from CommandQueue
singleton also doesn't fix it.
I know the lifetime scope for a shared_ptr is a singleton by default but I thought that was referred to the injected dependency not the actual object created with create.
Upvotes: 2
Views: 1256
Reputation: 393084
Indeed the simplest thing could be
auto button1 = injector.create<Control>();
auto button2 = injector.create<Control>();
std::cout << "button1.id = " << button1.id() << std::endl;
std::cout << "button2.id = " << button2.id() << std::endl;
Prints
button1.id = 1
button2.id = 2
If you must have shared-pointers, the next simplest thing would be
auto button1 = std::make_shared<Control>(injector.create<Control>());
auto button2 = std::make_shared<Control>(injector.create<Control>());
std::cout << "button1->id = " << button1->id() << std::endl;
std::cout << "button2->id = " << button2->id() << std::endl;
Conceptually you want a control-factory, not a control. So, you should consider creating a factory from the dependency container:
#include <boost/di.hpp>
#include <iostream>
#include <memory>
namespace di = boost::di;
struct CommandQueue {
void addCommand() {}
};
struct Control {
Control(CommandQueue &cq) : _cq(cq), _id(idgen()) { }
int id() const { return _id; }
struct Factory {
Factory(CommandQueue& cq) : _cq(cq) {}
CommandQueue& _cq;
template <typename... Args>
auto operator()(Args&&... args) const {
return std::make_shared<Control>(_cq, std::forward<Args>(args)...);
}
};
private:
static int idgen() { static int sid{}; return ++sid; }
CommandQueue &_cq;
int _id{};
};
int main() {
auto injector = di::make_injector(di::bind<CommandQueue>().in(di::singleton));
auto factory = injector.create<Control::Factory>();
auto button1 = factory();
auto button2 = factory();
std::cout << "button1->id = " << button1->id() << std::endl;
std::cout << "button2->id = " << button2->id() << std::endl;
}
Upvotes: 3