如何禁止调用临时对象的成员函数(C++)
How forbid to call member function for temporary object (C++)
我有模板 class data_ptr
,其中的成员 operator *
用于访问数据指针:
operator T*() { return m_pPtr; }
同样在 data_ptr
的构造函数中,它的指针在内存中是 "pinned",在析构函数中是 "unpinned".
我想禁止使用operator*
是这样的:
data_ptr<T> GetSomeDataPtr { return data_ptr<T>(...); }
T *pRawPointerToData = *GetSomeDataPtr();
...因为函数GetSomeDataPtr
returns 临时对象data_ptr
,并且当析构函数被调用时它的数据指针变得无效,所以我们在访问时发生崩溃pRawPointerToData
.
所以,主要思路是使用编译器来查找这样的代码。我正在使用 Visual Studio 2015 更新 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;
}
您可以使用 左值引用限定符 声明 operator T*
,即
operator T*() & { return p; }
以便只能对 data_ptr
的左值调用此转换,这意味着禁止临时(右值)调用此转换。
您的设计也存在一些缺陷。即使一个对象不是临时对象,它也会在稍后的某个时间被销毁,而之前暴露的那些T*
不知道销毁,这有潜在的无效访问的危险。因此,调用者有责任保证没有无效访问,因此您不必限制对临时对象的调用。例如,std::string::c_str
没有此类限制。
我有模板 class data_ptr
,其中的成员 operator *
用于访问数据指针:
operator T*() { return m_pPtr; }
同样在 data_ptr
的构造函数中,它的指针在内存中是 "pinned",在析构函数中是 "unpinned".
我想禁止使用operator*
是这样的:
data_ptr<T> GetSomeDataPtr { return data_ptr<T>(...); }
T *pRawPointerToData = *GetSomeDataPtr();
...因为函数GetSomeDataPtr
returns 临时对象data_ptr
,并且当析构函数被调用时它的数据指针变得无效,所以我们在访问时发生崩溃pRawPointerToData
.
所以,主要思路是使用编译器来查找这样的代码。我正在使用 Visual Studio 2015 更新 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;
}
您可以使用 左值引用限定符 声明 operator T*
,即
operator T*() & { return p; }
以便只能对 data_ptr
的左值调用此转换,这意味着禁止临时(右值)调用此转换。
您的设计也存在一些缺陷。即使一个对象不是临时对象,它也会在稍后的某个时间被销毁,而之前暴露的那些T*
不知道销毁,这有潜在的无效访问的危险。因此,调用者有责任保证没有无效访问,因此您不必限制对临时对象的调用。例如,std::string::c_str
没有此类限制。