我正在创建一个TextField类,该类当前存储对变量的引用,并且只要程序员需要,他们可以调用TextField.show()和引用的变量将被读取并显示在屏幕上。确保不会失效的引用
但是,如果引用变为无效,这可能会导致问题。例如,如果引用的变量超出了范围,那么我遇到了问题。
基本上,有没有什么办法可以确保用户给出的参考不会失效?或者,有没有更好的方法来建立这个系统?或者如果没有,在这种情况下处理无效引用的最佳方法是什么?
我正在创建一个TextField类,该类当前存储对变量的引用,并且只要程序员需要,他们可以调用TextField.show()和引用的变量将被读取并显示在屏幕上。确保不会失效的引用
但是,如果引用变为无效,这可能会导致问题。例如,如果引用的变量超出了范围,那么我遇到了问题。
基本上,有没有什么办法可以确保用户给出的参考不会失效?或者,有没有更好的方法来建立这个系统?或者如果没有,在这种情况下处理无效引用的最佳方法是什么?
如果您使用引用,则调用者的责任是确保他/她的代码不是未定义的。基本上,没有办法知道。您可以使用shared_ptr
来确保不会发生此问题,并允许共享所有权。这意味着如果变量(shared_ptr
)超出范围,则该值不会被破坏,除非没有其他人指向它自己的值。
有参考,没有。你不能说,因为C++不会自动让你知道引用正在被销毁。
如果你切换到使用指针,你会得到一些选择。正如上面已经提到的那样,一个是使用shared_ptr
。如果你知道你的TextField对象将会显示其中的对象,那么另一个方法是可用的,就是在该变量周围创建一个包装类,它将获取指向TextField的指针并通知包装器的析构函数中的文本字段。
例如,下面是一个包装类,它会在std :: string超出范围时通知您的TextField。
在包装类的头文件:
// Wraps a pointer to a string, which TextField(s) will use.
// Notify the fields using it when it goes out of scope.
class WatchedPtr
{ string * ptrS_;
std::set<TextField*> watchers_;
static void NotifyOfDeath(TextField *watcher);
WatchedPtr(const WatchedPtr&); // Prevent copying.
WatchedPtr& operator=(const WatchedPtr&); // Prevent copying.
public:
WatchedPtr(string *s) : ptrS_(s) {}
void addWatcher (TextField *watcher) { watchers_.insert(watcher); }
void removeWatcher(TextField *watcher) { watchers_.erase(watcher); }
~WatchedPtr()
{ std::for_each(watchers_.begin(), watchers_.end(), NotifyOfDeath);
delete ptrS_;
ptrS_ = NULL;
}
string* get() { return ptrS_; }
};
在包装类CPP文件:
void WatchedPtr::NotifyOfDeath(TextField *watcher)
{ if(watcher)
{ watcher->clientIsDead();
}
}
在TextField类的头文件:
class TextField
{
string *text_;
public:
TextField() : text_(NULL) {}
void SetTextRef(WatchedPtr &wp)
{ text_ = wp.get();
wp.addWatcher(this);
}
void show()
{ if(text_)
{ cout << "Drawing textfield with text [" << (*text_) << "]" << endl;
}
else
{ cout << "String is not valid. Drawing empty text box." << endl;
}
}
void clientIsDead() { text_ = NULL; } // do not trust the pointer anymore.
};
使用的一个例子:
int main(int argc, char* *argv)
{
TextField tf;
{ WatchedPtr ptrString(new string("Some Text"));
tf.SetTextRef(ptrString);
tf.show(); // uses the string.
} // ptrString's destructor tells TextField to stop trusting the pointer.
tf.show(); // string is not used.
return 0;
}
虽然这有点脆弱,并不像完全共享指针那样灵活,但如果您无法访问shared_ptr,则可能会很有用。如果您的TextField在WatchedPtr仍然存在的情况下被销毁,它将失败,因为当WatchedPtr尝试在析构函数中使用它时,回调指针将会失效。然而,它可以在许多例子中工作,例如,许多项目更新的状态栏文本或许多对象可能更改的进度栏中的文本。 (这是一个简化的例子,它可以在很多方面得到改进,比如对WatchedPtr进行模板化,使其适用于除字符串之外的其他类,传递函数对象或指针,以便观察者可以与TextField等其他类一起使用)