I have written a class to encapsulate pointers for a platform, where the STL is not available. The idea is to have something similar to std::shared_ptr.However, I don't want to delete the encapsulated object automatically, once the last reference is gone.Instead, I force the application code to do so by asserting.template <typename T>class checked_ptr {private:    struct checked_object_wrapper {        T* raw_instance;        int reference_count;    };    checked_object_wrapper* wrapped_object;    checked_ptr(checked_object_wrapper* const object) : wrapped_object{object} {    }public:    checked_ptr() : wrapped_object{nullptr} {    }    checked_ptr(const checked_ptr& other) : wrapped_object{other.wrapped_object} {        if(this->wrapped_object) {            this->wrapped_object->reference_count++;        }    }    checked_ptr(checked_ptr&& other) : wrapped_object{other.wrapped_object} {        other.wrapped_object = nullptr;    }    checked_ptr(T*&& raw) : checked_ptr{new checked_object_wrapper{raw, 1}} {    }    ~checked_ptr() {        reset();    }    checked_ptr& operator=(const checked_ptr& other) {        ASSERT(this->wrapped_object == nullptr);        if(this->wrapped_object != other.wrapped_object) {            this->wrapped_object = other.wrapped_object;            if(this->wrapped_object) {                this->wrapped_object->reference_count++;            }        }        return *this;    }    checked_ptr& operator=(checked_ptr&& other) {        ASSERT(this->wrapped_object == nullptr);        this->wrapped_object = other.wrapped_object;        other.wrapped_object = nullptr;        return *this;    }    bool operator==(const checked_ptr& other) const {        return this->wrapped_object == other.wrapped_object;    }    bool operator!=(const checked_ptr& other) const {        return this->wrapped_object != other.wrapped_object;    }    void reset() {        if(this->wrapped_object) {            this->wrapped_object->reference_count--;            ASSERT(this->wrapped_object->reference_count > 0);            this->wrapped_object = nullptr;        }        return;    }    /**     * This should only be used during deconstruction at the end of the runtime     */    void force_reset() {        if(this->wrapped_object) {            this->wrapped_object->reference_count--;            if(this->wrapped_object->reference_count == 0) {                delete this->wrapped_object->raw_instance;                delete this->wrapped_object;            }            this->wrapped_object = nullptr;        }        return;    }    T* get() {        if(this->wrapped_object) {            return this->wrapped_object->raw_instance;        } else {            return nullptr;        }    }    T& operator*() {        ASSERT(this->wrapped_object != nullptr);        ASSERT(this->wrapped_object->raw_instance != nullptr);        return *(this->wrapped_object->raw_instance);    }    T* operator->() {        ASSERT(this->wrapped_object != nullptr);        ASSERT(this->wrapped_object->raw_instance != nullptr);        return this->wrapped_object->raw_instance;    }    const T* operator->() const {        ASSERT(this->wrapped_object != nullptr);        ASSERT(this->wrapped_object->raw_instance != nullptr);        return this->wrapped_object->raw_instance;    }    long int use_count() const noexcept {        if(this->wrapped_object) {            return this->wrapped_object->reference_count;        } else {            return 0;        }    }    explicit operator bool() const noexcept {        return this->wrapped_object != nullptr;    }    bool unique() const noexcept {        return use_count() == 1;    }    void deleteObject() {        ASSERT(unique());        if(this->wrapped_object) {            this->wrapped_object->reference_count--;            ASSERT(this->wrapped_object->raw_instance != nullptr);            delete this->wrapped_object->raw_instance;            delete this->wrapped_object;            this->wrapped_object = nullptr;        }    }};This utility function can be used like std::make_shared to create fresh instances to new objects:template <typename T, typename... A>checked_ptr<T> make_checked(A&&... arg) {    return checked_ptr<T>{new T{arg...}};}I wrote this class to deal with objects being lost and not deleted by my code and I expected that this class would find all memory leaks.Any thoughts on this? Especially the additional dynamically allocated memory for my checked_object_wrapper gives me a headache, but I couldn't figure out a better way to store the meta information (the reference count) in a generic fashion. (Note the additional requirement that I can't always use make_checked to create new instances, sometimes I have to use pointers that come from other libraries. Hence, the public constructor that takes a raw pointer is necessary.)
Custom checked_ptr (like std::shared_ptr) for projects without STL
c++;memory management