2016-10-10 92 views
6

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

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原则,同时仍然保持高效的内存?

+0

你可以让'lib_api *'成为deleter类的静态成员吗​​? – Brian

+0

我认为你需要将'freeInstance'存储在容器类的自定义派生类中,并且你的容器将包含'lib_object *'。在派生类中,您必须实现将在每个元素上调用'freeInstance'的析构函数。 – Franck

回答

5

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

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

+0

我想到了这一点,似乎全局变量是唯一有用的解决方案。 – 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; 

而且其规模仍然等于一个指针。 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>> 

这似乎更加缓存繁重,但可能只是你的东西。

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

相关问题