I haven’t used std::unique_ptr much and wasn’t aware that you could supply a custom deletor.

If you provide the deleter as template argument (as in unique_ptr) it is part of the type and you don’t need to store anything additional in the objects of this type. If deleter is passed as constructor’s argument (as in shared_ptr) you need to store it in the object. This is the cost of additional flexibility, since you can use different deleters for the objects of the same type

Since unique_ptr is lightweight and doesn’t have the overhead of a control block, it uses a template parameter for the deletor. std::shared_ptr takes the other choice since it already has a control block and gains the extra flexibility.