Is there / should there be a way to track the validity of a raw pointer taken from a smart pointer for debug/QA purposes?

自作多情 提交于 2019-12-11 17:34:25

问题


As I understand C++ Core Guidelines by Bjarne Stroustrup & Herb Sutter, it is a good idea to use pointers this way:

  • unique_ptr for the good old clear one ownership
  • shared_ptr for truly shared ownership by design
  • weak_ptr when by design the pointer might not be valid anymore
  • raw pointer whenever the pointer is valid by design, and ownership is unchanged

Thus theoretically it still may be a common bug that a raw pointer becomes invalid (see R37).
I wonder if there is a way for debug/QA purposes, to make an assertion of the validity of the raw pointer. I believe such checks can help improve stability of programs dramatically.

I have written the following possible implementation. My question:
What do you think about having such code? Does it make sense to you? Does something like this exist? Any other comments?

At this stage incompleteness of the implementation is not so important (thread safety or other stuff), unless it reflects a reason for not doing it.

#include <memory>
#include <cassert>

#if NDEBUG

template <typename T>
using WatchedPtr = T*;

template <typename T>
T* get (const std::shared_ptr<T>& p) {return p.get();}

#else

template <typename T>
class WatchedPtr {
    template <typename T1>
    friend WatchedPtr<T1> get (const std::shared_ptr<T1>& p);

public:
    WatchedPtr() : _ptr (nullptr) {}

    operator T* () { return getPtr();}

    T* operator->() const { assert (getPtr()); return getPtr(); }

    T& operator*() const { assert (getPtr()); return *getPtr(); }

private:
    T* getPtr () const { return _weak.expired () ? nullptr : _ptr;}
    WatchedPtr(std::shared_ptr<T> p) : _weak (p) {
        _ptr = _weak.lock().get();
    }
    std::weak_ptr<T> _weak;
    T* _ptr;
};

template <typename T1>
inline WatchedPtr<T1> get (const std::shared_ptr<T1>& p) {return WatchedPtr<T1> (p);} //because I cannot change the get() member

#endif

Usage example:

void f (WatchedPtr<int> p) {
    assert(p);//detects errors
    *p = 3;//detects errors
    std::cout << "f: *p=" << *p << std::endl;
}

void g (int* p) {
    assert(p);//detects errors
    *p = 3;//does not detect error
    std::cout << "g: *p=" << *p << std::endl;
}

int main () {
    WatchedPtr<int> p;

    {
        auto pp = std::make_shared<int> (1234);
        p = get(pp);
        f (p);
    }
    f (p);
    g (p); //the internal assert() of g() will detect errors, because casting of invalid p to raw pointer will be nullptr
}

*I thought of implementing also for unique_ptr. But so far my only idea is to store a pointer to unique_ptr in WatchedPtr. This will identify errors only on some of the cases, where get() or bool operator will crash or return nullptr.

来源:https://stackoverflow.com/questions/56093808/is-there-should-there-be-a-way-to-track-the-validity-of-a-raw-pointer-taken-fr

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!