我想知道是否可以在取消引用指针时添加代码(实际指向的对象的有效性检查)。 我在重载运算符上看到了很多主题 - >,但似乎操作符是在对象上调用的,而不是指针。也许(可能)有一些我误解的事情。
这是一个例子:
T* pObj = new T();
pObj->DoStuff(); // call check code (not in DoStuff)
delete pObj;
pObj->DoOtherStuff(); // call check code (not in DoOtherStuff)
“检查代码”应独立于所调用的函数(或成员)。我的想法是在类中将一个成员设置为一个int,并在构造(和销毁)时给它一个定义的值,然后检查该值。
您可能已经猜到我会尝试检查使用的无效指针。我尝试阅读代码,但它太大而复杂,不会错过很多潜在的错误。
感谢您的回答和见解。
答案 0 :(得分:3)
operator->
只能作为类的成员函数重载,而不能作为普通指针重载。
通常,无法检查(非空)指针实际上是否指向有效对象。在您的示例中,delete pObj;
不会更改指针;它只是让它指向无效的内存,并没有办法测试它。所以,即使你可以在这里重载operator->
,它能做的最好的事情就是检查它是否为空。
通常的方法是使用智能指针,而不是普通的指针。智能指针是一个包含指向对象的普通指针的类,并且具有operator*
和operator->
的重载,因此它看起来像一个指针。您不会直接删除对象,而是通过指针(当它超出范围时,或通过调用reset()
函数显式删除),然后指针可以在发生这种情况时将其普通指针设置为null。这样,普通指针将始终有效或为null,因此重载运算符可以在解除引用之前对其进行有效检查。
智能指针(以及一般的RAII)也带来了其他优势:自动内存管理和异常安全。在您的代码中,如果DoStuff()
抛出异常,则会发生内存泄漏; pObj
将超出范围,因此无法访问它以删除它指向的对象。内存将丢失,如果这种情况不断发生,您最终将使用系统的所有内存,无论是崩溃还是缓慢爬行。如果它是一个智能指针,那么该对象将在超出范围时自动删除。
标准库和Boost中常用的智能指针是auto_ptr
,scoped_ptr
和shared_ptr
,每个指针在复制指针时都有不同的行为。 C ++ 0x将引入unique_ptr
来替换auto_ptr
。
答案 1 :(得分:0)
正如尼克已经指出的那样,使用std :: auto_ptr或更好(如果可能的话)使用boost :: shared_ptr。它基本上实现了你想要的几乎。
直接回答这个问题:的确,你只能重载operator->对于一个类,所以在这种情况下,你将无法将它应用于该类的指针。换句话说,它将适用于对象,而不是指针。
class T {
T& operator->() { }
};
void f() {
T* pObj = new T();
pObj->DoStuff(); // Calls DoStuff, but... Oops! T::operator->() was not called!
(*pObj).DoStuff(); // Equivalent to the above
delete pObj;
(*pObj)->DoStuff(); // T::operator->() is called, but
// there is no improvement here: the pointer is dereferenced
// earlier and since it was deleted, this will "crash" the application
//pObj->->DoStuff(); // Syntactically incorrect, but semantically equivalent
//to the above
pObj->operator->()->DoStuff(); // Semantically equivalent to the above two,
//but avoids the double member access operator.
}
答案 2 :(得分:0)
operator ->
(或任何其他运算符)只能为类对象而不是指针重载。对于您的情况,您可以考虑使用标准/ cutom 智能指针(实际上是对象而不是指针,但它们可以用作指针)。
如果无法使用智能指针,请在NULL
之后进行delete/free
分配。或者您可以将自定义包装用于delete
,例如:
template<typename T>
void Destroy (T *&p) // use this wrapper instead of 'delete'
{
delete p;
p = 0;
}
答案 3 :(得分:0)
你应该重载运算符 - &gt;和*,或多或少与auto_ptr的工作方式相同。 例如:
template<typename T>
class SafePtr {
public:
SafePtr(T*p) : ptr(p) {}
T &operator*()
{
if ( !preConditions() ) {
throw runtime_error( "preconditions not met" );
}
return *ptr;
}
T * operator->()
{
if ( !preConditions() ) {
throw runtime_error( "preconditions not met" );
}
return ptr;
}
bool preConditions()
{ return ( ptr != NULL ); }
private:
T* ptr;
};
这可能是一个非常基本的例子。 - &gt;运算符会以类似的方式重载。在解除引用指针之前要执行的所有逻辑都将在preConditions()内编码。我想你可以从这里得到这个想法,如果没有,你可以进一步询问。
希望这有帮助。