有条件地使用RAII的最佳方式

时间:2011-06-17 19:42:27

标签: c++ raii

我有一个很好的资源管理类。具体来说,让它成为一个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
    }
}

(但不那么丑陋,更健壮,等等......)

4 个答案:

答案 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(...);
    }
};