我有模板类data_ptr
,其成员operator *
用于访问数据指针:
operator T*() { return m_pPtr; }
在data_ptr
的构造函数内部,它的指针在内存中“固定”,在析构函数中是“未固定”。
我想以这种方式禁止使用operator*
:
data_ptr<T> GetSomeDataPtr { return data_ptr<T>(...); }
T *pRawPointerToData = *GetSomeDataPtr();
...因为函数GetSomeDataPtr
返回临时对象data_ptr
,并且当析构函数被调用时,其数据指针变为无效,因此我们在访问pRawPointerToData
时会崩溃。
因此,主要思想是使用编译器来查找这样的代码。我正在使用Visual Studio 2015 Update 3。
例:
template <class T> class data_ptr
{
public:
data_ptr(T val) : p(new T(val)) {}
~data_ptr() {delete p;}
operator T*() { return p; }
private:
T *p;
};
template <class T>
data_ptr<T> GetSomeDataPtr(T val)
{
return data_ptr<T>(val);
}
int main()
{
int &rawReferenceToData = *GetSomeDataPtr<int>(123);
rawReferenceToData = 456; // << invalid access to already deleted object!
return 0;
}
您可以使用左值ref ref限定符声明operator T*
,即
operator T*() & { return p; }
因此,只能为data_ptr
的左值调用此转换,这意味着禁止临时(rvalue)调用此转换。
您的设计也存在一些缺陷。即使一个物体不是暂时的,它也会在某个时间被破坏,而之前暴露的那些T*
s不知道破坏,这可能导致无效访问。因此,调用者有责任保证不会进行无效访问,因此您不必为临时对象限制此调用。例如,std::string::c_str
没有这样的限制。