我有一个很好的资源管理类。具体来说,让它成为一个File类来管理FILE *(处理打开和关闭操作)
如果资源不需要由我管理,并且是其他人的责任,那么通常的做法是什么?
出于目的,我目前有这样的事情:
int main(int argc, char** argv)
{
File my_file(argv[1]); //I unconditionaly obtain the resource
//...
return 0; //and unconditionally relinquish with the destructor
}
想要像
这样的东西int main()
{
if(argc <= 1){
//use stdin that is already available
}else{
//obtain a file from argv[1]
}
//...
if(argc <= 1){
//nothing to do
}else{
//close the file we obtained
}
}
(但不那么丑陋,更健壮,等等......)
答案 0 :(得分:6)
boost::shared_ptr
允许您传入自定义析构函数。如果要包装外部管理的指针,则可以传递no-op:
namespace {
template<typename T>
void noop_destruct(T *) throw() { }
}
template<typename T>
boost::shared_ptr<T> make_dummy_shared_ptr(T *p) {
return boost::shared_ptr<T>(p, noop_destruct);
}
现在当你需要一个真正的RAII对象时,使用普通的boost::shared_ptr
,当你需要一个假的时候,使用这样的适配器 - 它的行为就像一个普通的指针。
答案 1 :(得分:2)
您可以推送是否在资源管理类中使用资源的逻辑。那就不再有条件了。只是做
int main(int argc, char** argv)
{
File my_file(argc > 1 ? argv[1]: NULL); //If NULL, File will point to stdin
//...
return 0; //File's destructor will run, relinquishing resources if necessary.
}
答案 2 :(得分:2)
你的RAII类已经保持足够的状态来知道何时销毁它所控制的资源。它还可以包含一个标志,告诉它是否应该销毁资源,或者您可以在计数器上使用特殊值来指示资源是在类外控制的。
然后,您只需要一种在获取资源时控制状态的方法。例如,您可以使用两个不同的构造函数,或者构造函数上的参数具有默认值。您可以使用Attach
方法附加现有资源。这完全取决于你。
答案 3 :(得分:0)
最常见的模式不允许这样做。但是,您可以允许自定义分配器插件,标准具有它的容器,这将允许这些语义。这是一个简短的样本 -
class Allocator {
File* Allocate(...) {
return fopen(...);
}
};
class MyStdinAllocator {
File* Allocate(...) {
return ...;
}
};
template<typename MyAllocator = Allocator> class File {
File* ptr;
Allocator alloc;
File(..., const Allocator& allocref)
: alloc(allocref) {
ptr = alloc.Allocate(...);
}
};