unique_ptr删除开销

时间:2016-10-10 20:30:21

标签: c++ c++11 smart-pointers raii

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

typedef struct lib_object lib_object;

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

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

3 个答案:

答案 0 :(得分:5)

如果只有一个lib_api对象,那么你可以让你的删除器获得一个静态指针。

如果可以有多个lib_api对象,那么您别无选择,只能在Deleter中存储指向它的指针。

答案 1 :(得分: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;

它的大小仍然等于一个指针。 live demo

来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;

live demo

有了这个,在你的情况下我会保留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>>

这似乎更加缓存,但可能只是你的事情。

答案 2 :(得分: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