I have the template class data_ptr
which has the member operator *
for access to the pointer to data:
operator T*() { return m_pPtr; }
Also inside the constructor of data_ptr
its pointer is "pinned" in memory and in destructor is "unpinned".
I want to forbid using the operator*
is this way:
data_ptr<T> GetSomeDataPtr { return data_ptr<T>(...); }
T *pRawPointerToData = *GetSomeDataPtr();
... because the function GetSomeDataPtr
returns the temporary object data_ptr
, and when the destructor gets called its data pointer becomes invalid, so we get a crash when accessing the pRawPointerToData
.
So, the main idea is to use compiler to find such code. I am using Visual Studio 2015 Update 3.
Example:
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;
}
You can declare operator T*
with an lvalue ref-qualifier, i.e.
operator T*() & { return p; }
so that this conversion can be called only for a lvalue of data_ptr
, which means a temporary (rvalue) is forbidden to call this conversion.
There are also some defects with your design. Even if an object is not a temporary, it will be destroyed later at some time, and those T*
s previously exposed do not know the destroy, which has potential danger of invalid access. As a result, it is the caller's responsibility to guarantee no invalid access, so you don't have to limit this call for temporary objects. As an example, std::string::c_str
can be called on temporaries.