c++lvalue

How forbid to call member function for temporary object (C++)


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;
}

Solution

  • 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.