据我所知C++ Core Guidelines by Bjarne Stroustrup & Herb Sutter,以这种方式使用指针是一个好主意:
因此,从理论上讲,原始指针可能仍然是一个常见的错误(请参见R37)。
我想知道是否有一种用于调试/ QA目的的方法来断言原始指针的有效性。我相信这样的检查可以帮助大大提高程序的稳定性。
我写了以下可能的实现。我的问题:
您对拥有这样的代码有什么看法?这对您有意义吗?是否存在这样的东西?还有其他评论吗?
在此阶段,实现的完整性并不那么重要(线程安全性或其他方面),除非它反映了不这样做的原因。
#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
用法示例:
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
}
*我想过也要为unique_ptr实现。但是到目前为止,我唯一的想法是在WatchedPtr中存储一个指向unique_ptr的指针。这只会在某些情况下识别错误,其中get()或bool运算符将崩溃或返回nullptr。