【问题标题】:Generic handle that auto releases resource [duplicate]自动释放资源的通用句柄[重复]
【发布时间】:2015-09-29 19:40:30
【问题描述】:

STL 或 boost 中是否有通用句柄类?我正在与一些具有分配、发布 api 的 C 代码交互。我想使用句柄来自动释放资源。

例如:

some_resource_type rsc;  
int err = capi_alloc(&rsc);
if (err != NOERR) {
   // .. do work with resource

   capi_release(rsc);
}  

我想要类似的东西

// looking for this class
class wrapper { 
public:
     wrapper(T obj, void (del)(T&)):obj(obj_),del_(del) {}
     ~wrapper() {_del(obj);}
     T obj_;
     void (del_)(T&);
};

some_resource_type rsc;  
int err = capi_alloc(&rsc);
wrapper w;
if (err != NOERR) {
    w = wrapper(rsc, &capi_release);
    // .. do work with resource
}  
// then auto release

在 STL 或 boost 中有类似的东西吗?它本质上是一些具有自定义创建和自定义删除的独特指针实现。

附:我还没有编译包装器代码,它可能不起作用。

【问题讨论】:

  • 不久前有人问过这个问题。你还没有搜索过。
  • @LightnessRacesinOrbit 我花了 30 分钟研究。我可能没有使用正确的关键词。如果你知道在哪里,请发个链接,谢谢。

标签: c++ boost stl


【解决方案1】:

你想要的是一个智能指针,这些是在最近的 C++ 和几乎所有可满足的 Boost 变体中;如果您使用的是 C++11,请将 boost 替换为 std

  • boost::shared_ptr
  • boost::weak_ptr

【讨论】:

  • 智能指针会动态分配some_resource_type。据我了解,OP 想在堆栈上分配它。
  • 你是对的:如果你在栈上声明你的智能指针,它所指向的东西必须在堆外分配。当智能指针超出范围时,它会自动清理内存。
  • @zenith,正如 Brian 暗示的那样,这包括调用对象的析构函数,这可能会释放对象保留的任何外部资源。
  • 智能指针根本不分配任何东西。你给他们已经分配的数据并告诉他们如何删除它,当它们超出范围时他们会为你清理。
【解决方案2】:

您实际上可以(ab)使用std::unique_ptr 及其第二个模板参数(自定义释放器):

std::unique_ptr<some_resource_type, void (&)(some_resource_type*)> w(nullptr, &capi_release);

然后在你的if:

w.reset(&rsc);

警告一句:您必须声明w 之后 rsc 使用这种方法。否则rsc 将在w 调用capi_release 之前被销毁。

但是,由于这不是 unique_ptr 的预期用途,我建议您简单地编写一个小型包装类,如我的其他答案所示。

【讨论】:

  • 我也试过了,也可以。谢谢。我将定义简化为 std::unique_ptr w(nullptr, &capi_release);我希望您看到这个问题很有帮助,因为另一个问题虽然相似,但不包含通用答案。
【解决方案3】:

由于std::unique_ptr 仅支持堆分配,不支持自定义分配器,因此您可以汇总自己的基于堆栈的包装类:

template<class T, int (& Allocator)(T*), void (& Deallocator)(T*)>
class wrapper {
public:
    wrapper() : err_(Allocator(&obj_)) {}
    ~wrapper() { if (err_ != NOERR) Deallocator(&obj_); }
    T& obj() { return obj_; }
    int err() { return err_; }
private:
    T obj_;
    int err_;
};

并像这样使用它:

wrapper<some_resource_type, capi_alloc, capi_release> rsc;  // capi_alloc called
if (rsc.err() != NOERR) {
    // .. do work with rsc.obj()
}
// capi_release called when rsc goes out of scope (if err_ != NOERR)

如果您在编译时不知道分配器和释放器函数是什么,那么只需将它们传递给构造函数并存储为成员数据。

【讨论】:

    猜你喜欢
    • 2023-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多