unique_ptr deleter开销

7

在普通的C++设计中,大多数对象可以通过delete语句、free函数或类库特定等效的free来删除。对于这些对象,unique_ptrDeleter实现可以是一个无状态对象,通过空基类优化消除。然而,一些库要求使用另一个对象(可能包含函数指针或其他上下文)来从该库中删除对象。

typedef struct lib_object lib_object;

struct lib_api {
  lib_object (*createInstance)();
  void (*freeInstance)(lib_object *o);
};

可以通过将lib_api指针存储为自定义Deleter中的数据成员,然后将其包装在unique_ptr中来实现。但是,如果需要管理多个lib_object实例(例如在容器中),则会使跟踪这些对象的内存开销加倍。在处理此库时如何使用模式来保持RAII原则,同时仍保持内存效率呢?


你能把 lib_api* 设为删除器类的静态成员吗? - Brian Bi
我认为你需要将freeInstance存储在容器类的自定义派生类中,并且你的容器将包含lib_object*。在派生类中,你必须实现析构函数,该函数将在每个元素上调用freeInstance - Franck
3个回答

5
如果只有一个 lib_api 对象,那么您可以让删除器获取一个静态指针来引用它。
如果可能存在多个 lib_api 对象,则您只能将指针存储在删除器中。

我思考了一下,似乎全局变量是唯一有用的解决方案。 - 68ejxfcj5669

2

我会使用自定义删除器模板来处理这类对象。

template<typename T, T Function>
struct function_deleter
{
    template<typename U>
    auto operator()(U&& u) const noexcept(noexcept(Function(std::forward<U>(u))))
    {
        return Function(std::forward<U>(u));
    }
};

那么你可以使用你的删除器调用free

unique_ptr<int, function_deleter<void(*)(void*), &free>> uniq;

它的大小仍然等于一个指针。演示

到了C++17,您将能够使用auto来代替非类型模板参数,从而简化代码:

template<auto Function>
struct function_deleter
{
    template<typename U>
    auto operator()(U&& u) const noexcept(noexcept(Function(std::forward<U>(u))))
    {
        return Function(std::forward<U>(u));
    }
};

并且。
unique_ptr<int, function_deleter<&call_free>> uniq;

演示

在您的情况下,我建议使用具有静态删除器的unique_ptr<pair<lib_object, lib_api>>来支持此结构。

using lib_pair = pair<lib_object, lib_api>;

void lib_free(lib_pair* p){
    p->second.freeInstance(p->first);
    delete p;
}


using unique_lib_ptr = unique_ptr<lib_pair, function_deleter<void(*)(lib_pair*), &lib_free>>

这似乎更加依赖缓存,但可能正是你需要的东西。

0

应该存在更优雅的解决方案,但我会写出类似的代码

template <class ContainerType>
class TObjectContainer : public ContainerType {
  public:
   TObjectContainer() = default;
   TObjectContainer(const TObjectContainer&); // should call createCopy 
   TObjectContainer(TObjectContainer&&) = default;
   ~TObjectContainer()
     { for (lib_object* element : *this)
         (*freeInstance)(element);
     }

  private:
   void (*freeInstance)(lib_object *o);
};

typedef TObjectContainer<std::vector<lib_object*>> ObjectVector;

它不使用unique_ptr,但基本上应该能够完成工作。

请注意,您可能会重载每个删除方法,例如clear以调用freeInstancepop_back以返回原始的std::unique_ptr


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接