Smart pointers in a factory constructor seem to force the created object to know how it's being used

Viewed 44

I am using a factory to create some objects at runtime based on some user selections.

So I have something like this currently:

class UpdateServiceFactory{
  public:
    std::unique_ptr<UpdateService> create(Widget widget){
       if(widget.name == "name one"){
          auto dependency = std::make_unique<ChildDependency>();
          return std::make_unique<ChildUpdateService>(std::move(dep));
       }
  }
}

My ChildUpdateService can:

a) take a unique pointer to its dependency. On one hand, this seems ideal, because I want my dependency to go out of scope when my UpdateService is destroyed. But on the other hand, I am now forcing a lifetime policy on the creator of the object from an object that shouldn't really care about it, just for the sake of easy cleanup of the memory. For example, my ChildUpdateService has no idea if the factory wants to pass the same dependency it just created to another class as well, which a unique pointer would make impossible. And it seems I've now dictated that by specifying the smart pointer on my constructor.

b) I could take a raw dependency pointer into the constructor of the ChildUpdateService and pass it using unique_ptr::get. But now I have the issue of needing to manage the lifetime of the dependency pointer elsewhere. Something has to own it otherwise it's going to go out of scope as soon as the create function returns. At this point, the only object that knows about the pointer is my factory, but the factory shouldn't really be responsible for managing the pointer's lifetime either. Its job is to create the object and that's it. I feel like doing any more would be a violation of the SRP.

So my question is two fold, I suppose. 1) If a constructor takes a unique pointer, am I dictating a lifetime policy on the creator of the object that I shouldn't be? And 2) is there a pattern that solves this problem which I could (should) use, such as creating an intermediate object, whose job is to manage the lifetime of the dependency?

1 Answers

If you want your Service type to decide this, then you require its assistance when creating the Dependency. You could do it like this:

class ServiceBase { // you need this anyway
  public:
    virtual ~ServiceBase() {}
};
class ChildUpdateService : public ServiceBase {
  private:
    // now, the class itself defines that it wants to store a unique_ptr.
    // not the generic factory!
    ChildUpdateService(std::unique_ptr<ChildDependency>);
  public:
    template <typename Dep, typename... Args>
    static std::unique_ptr<ChildUpdateService> make(Args&&... args) {
      return std::make_unique<ChildUpdateService>(std::make_unique<T>(std::forward<Args>(args)...));
    }
};

If you have several Services like this, maybe create an intermediary class template that employs CRTP.

This means that your generic factory doesn't have to decide how the respective Service implementation keeps its dependency around (as unique_ptr, as shared_ptr, as automatic member, etc.).

class UpdateServiceFactory {
  public:
    std::unique_ptr<UpdateService> create(Widget widget) {
      if (widget.name == "name one")
        return ChildUpdateService::make<ChildDependency>();
    }
}
Related