Implementing my own shared-ownership double-indirecting smart-pointer I am implementing my own double-indirecting shared-ownership smart-pointer because I needed a way to replace the managed object a group of smart-pointers is pointing to with a new object (it's the method reset_all in the code below).

I tried to keep this as close as I could to the std::shared_ptr's interface, while avoiding things I don't understand / need like aliasing and conversion from other smart-pointer types.

//(it's all in an header file)
#pragma once

template &lt;typename T&gt;
class Manager {
    template &lt;typename U&gt;
    friend class SharedPtr;

    T* managed;
    unsigned int counter;

    Manager(T* new_ptr):
        managed(new_ptr), counter(1) {}
    ~Manager() = default;

    Manager&lt;T&gt;* own() {
        ++counter;
        return this;
    }
    void disown() {
        if (!(--counter)) {
            delete managed;
            delete this;
        }
    }
};

template &lt;typename T&gt;
class SharedPtr {
    public:
    SharedPtr() = default;
    SharedPtr(T* new_ptr) {
        if (new_ptr) {
            manager = new Manager&lt;T&gt;(new_ptr);
        }
    }
    SharedPtr(const SharedPtr &amp;rhs):
        manager(rhs.manager-&gt;own()) {}
    SharedPtr(SharedPtr &amp;&amp;rhs):
        manager(rhs.manager) {
        rhs.manager = nullptr;
    }

    SharedPtr&amp; operator=(const SharedPtr &amp;rhs) {
        if (manager) {
            manager-&gt;disown();
        }
        manager = rhs.manager-&gt;own();
        return *this;
    }
    SharedPtr&amp; operator=(SharedPtr &amp;&amp;rhs) {
        if (manager) {
            manager-&gt;disown();
        }
        manager = rhs.manager;
        rhs.manager = nullptr;
        return *this;
    }

    void swap(SharedPtr &amp;rhs) {
        Manager&lt;T&gt;* tmp = manager;
        manager = rhs.manager;
        rhs.manager = tmp;
    }

    void reset() {
        if (manager) {
            manager-&gt;disown();
        }
        manager = nullptr;
    }
    void reset(T* new_ptr) {
        if (manager) {
            manager-&gt;disown();
        }
        manager = new Manager&lt;T&gt;(new_ptr);
    }

    T* get() {
        if (manager) {
            return manager-&gt;managed;
        }
        return nullptr;
    }

    T&amp; operator*() {
        return *(manager-&gt;managed);
    }

    T* operator-&gt;() {
        return manager-&gt;managed;
    }

    unsigned int use_count() {
        if (manager) {
            return manager-&gt;counter;
        }
        return 0;
    }

    bool unique() {
        return use_count() == 1;
    }

    operator bool() {
        return (bool) manager;
    }

    void reset_all(T* new_ptr) {
        if (manager) {
            delete manager-&gt;managed;
            manager-&gt;managed = new_ptr;
            return;
        }
        manager = new Manager&lt;T&gt;(new_ptr);
    }

    ~SharedPtr() {
        if (manager) {
            manager-&gt;disown();
        }
    }

    private:
    Manager&lt;T&gt;* manager = nullptr;
};
I wouldn't call it SharedPtr because the contrast to a std::shared_ptr is too big, and the name too similar.
Maybe DoublePtr or alike to emphasize the double-indirection which is the crucial feature...
I would make Manager a private non-template member of your class, because it's an implementation-detail. Also, I would make it a dumb struct and put the useful function it contains (disown) into the private part of DoublePtr.
While having a default-ctor without allocation might be enough of a boon to allow a resourceless state (it probably is), there's no reason to disallow creating a pointer-group which starts as nullptr.
Thus I would remove the check in the ctor.
op= is wrong, try self-assignment. It should be disown after own.
op=(&amp;&amp;) would be better as a simple swap.
op(bool) is wrong: Use get() != nullptr.
reset and reset_all could easily be upgraded from basic to strong exception-safety (commit-or-rollback), just create a new DoublePtr and swap.
Many of your functions can and should be marked noexcept.
Also, pure observing methods should be marked const.