C++ 有条件地使用RAII的最佳方法

C++ 有条件地使用RAII的最佳方法,c++,raii,C++,Raii,我有一个很好的资源管理课。具体来说,让它成为一个文件类,用于管理文件*(处理打开和关闭操作) 当资源不需要由我管理,并且是其他人的责任时,通常的方法是什么 为了便于说明,我目前有如下内容: int main(int argc, char** argv) { File my_file(argv[1]); //I unconditionaly obtain the resource //... return 0; //and unconditionally relinqui

我有一个很好的资源管理课。具体来说,让它成为一个文件类,用于管理文件*(处理打开和关闭操作)

当资源不需要由我管理,并且是其他人的责任时,通常的方法是什么

为了便于说明,我目前有如下内容:

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
    }
}
intmain()
{

if(argc大多数常见模式都不允许这样做。但是,您可以允许自定义分配器插件(该标准为其容器提供)来支持这些语义。这是一个简单的示例-

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(...);
    }
};
类分配器{
文件*分配(…){
返回fopen(…);
}
};
类mystDiallocator{
文件*分配(…){
返回。。。;
}
};
模板类文件{
文件*ptr;
分配程序alloc;
文件(…,常量分配器&allocref)
:alloc(allocref){
ptr=分配分配(…);
}
};

您可以在资源管理类中推送是否使用资源的逻辑。这样它就不再是有条件的了。只需这样做即可

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.
}

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);
}
名称空间{
模板
void noop_析构函数(T*)throw(){}
}
模板
boost::shared_ptr make_dummy_shared_ptr(T*p){
返回boost::shared_ptr(p,noop_destruct);
}

现在,当你需要一个真正的RAII对象时,使用一个普通的boost::shared_ptr
,当你需要一个假的对象时,使用一个这样的适配器-它将完全像一个普通的指针一样工作。

你的RAII类已经保持足够的状态,知道什么时候销毁它控制的资源。它还可以包含一个标志,告诉它是否需要资源e应该被销毁,或者您可以在计数器上使用一个特殊的值来指示资源是在类之外控制的


然后,您所需要的就是在获取资源时控制状态的方法。例如,您可以有两个不同的构造函数,或者构造函数上的一个参数具有默认值。您可以有一个附加现有资源的
Attach
方法。这完全取决于您。

+1,我在一些地方。如果想要避免引用计数开销,也可以使用
unique\u ptr
来完成。unique\u ptr的缺点是@Ildjarn必须将deleter类型指定为模板参数,因此用于无操作情况的deleter必须与用于其他情况的deleter类型相同。@Rob:对--删除程序需要智能化这一事实被暗示了。:-]