2016-10-10 37 views
6

Normal C++ tasarımında, çoğu nesne delete bildirimi, free işlevi veya free numaralı kitaplığa özgü eşdeğeri ile silinebilir. Bu gibi nesneler için, unique_ptrDeleter uygulaması, Boş Temel Sınıf Optimizasyonu aracılığıyla elimine edilen durum bilgisi olmayan bir nesne olabilir. Bununla birlikte, bazı kitaplıklar, bu kitaplıktaki nesneleri silmek için başka bir nesneyi (bir işlev işaretçisi veya başka bir içerik içerebilir) kullanmayı gerektirir.unique_ptr deleter ek yükü

typedef struct lib_object lib_object; 

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

Bir özel bir Deleter bir veri elemanı gibi bir lib_api gösterici depolayarak unique_ptr bu kaydırmak ama olabilir gereken birden çok lib_object örneği yönetilmesini ise, örneğin, Bir kapsayıcıda, nesnelerin izlenmesinin bellek yükünü iki katına çıkarırdı. Bu kütüphaneyle uğraşırken RAII prensiplerini korumak için ne tür bir model kullanılabilir, ancak hafızada etkin kalır mı?

+0

"lib_api *', deleter sınıfının statik bir üyesini yapabilir misiniz? – Brian

+0

"freeInstance" ı kap sınıfının özel türetilmiş sınıfında depolamanız ve kapsayıcınızın 'lib_object *' içermesi gerektiğini düşünüyorum.Türetilmiş sınıfta, her elementte 'freeInstance' diyen yıkıcıyı uygulamak zorundasınız. – Franck

cevap

5

Yalnızca bir tane bir lib_api nesnesi varsa, bu durumda delicinizin buna statik bir işaretçi gönderebilirsiniz.

Birden fazla lib_api nesnesi varsa, Deleter'de bir işaretçiyi saklamaktan başka seçeneğiniz yoktur.

+0

Bunu düşündüm ve küresel değişkenler tek yararlı çözümdür. – 68ejxfcj5669

2

Bu tür nesneler için özel bir silme şablonu kullanıyorum.

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)); 
    } 
}; 

o zaman deleter çağrı free kullanmak olabilir:

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

Ve boyutu hala bir pointer eşittir.

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)); 
    } 
}; 

ve

unique_ptr<int, function_deleter<&call_free>> uniq; 

live demo

: live demo

Eğer kod basitleştirilmesi olmayan tip şablon parametreleri için auto kullanmak mümkün olacak C++ 17 Gel Bu durumda, bu yapıyı destekleyen statik bir delici ile bir unique_ptr<pair<lib_object, lib_api>> tutmak.

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

Bu daha fazla önbellek ağır gibi görünüyor, ancak yalnızca sizin bir şey olabilir.

0

daha zarif bir çözüm var olması gereken ama O unique_ptr kullanmaz

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; 

yazabiliriz ama işi temelde olmalıdır. senin freeInstance veya pop_back orijinal std::unique_ptr dönmek aramaya clear gibi her kaldırma yöntemini aşırı muhtemeldir

Not.