Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using an abstract deleter with std::unique_ptr

I want to have a run-time interface that offers some creation methods. These methods return unique_ptr<T>, and I want to enable custom deletion by the creating class. The thing is that I definitely don't want the interface to offer these methods directly- they should only be available in the destruction of the unique_ptr<T, SomeCustomDel>. Now, I figured that I can use std::unique_ptr<T, std::function<void(T*)>>, but I'd really rather not because I simply don't need that level of abstraction and I don't want to have to pay the heap allocation.

Any suggestions?

like image 828
Puppy Avatar asked Jun 12 '11 12:06

Puppy


2 Answers

Your specification isn't completely clear to me, but have you considered unique_ptr<T, void(*)(void*)>? This is a very flexible type with many qualities of a dynamic deleter.

If that isn't what you're looking for, you might try something along the lines of:

class impl
{
public:
    virtual ~impl();

    virtual void operator()(void*) = 0;
    virtual void other_functionality() = 0;
};

class my_deleter
{
    impl* p_;
public:
    ...
    void operator()(void* p) {(*p_)(p);}
    void other_functionality() {p_->other_functionality();}
    ...
};

It is difficult to know what is best in your case without more details about your requirements.

like image 113
Howard Hinnant Avatar answered Sep 29 '22 08:09

Howard Hinnant


I wish there was a standard "dynamic" deleter version of std::unique_ptr. This mythical class would allow me to attach a deleter to the unique_ptr when I instantiate it, similar to std::shared_ptr.

That said if such a type existed I suspect it would essentially be implemented with std::unique_ptr<T,std::function<void(T*)>>. The very thing you wanted to avoid.

However I think you're underestimating std::function. Its implementation is optimization to avoid hitting the heap if possible. If your deleter object remains small everything will be done on the stack (I think boost::function can statically handle deleters up to 32 bytes in size).

A for the problem of a too general deleter. You have to provide the definition of the deleter. There is no way around that. However you don't have to let the user instantiate the class, which essentially forbids them from using it. To do this make the deleter's constructor(s) require a tag structure that is only defined in the implementation file.

Or possibly the simplest solution. Put the deleter in a detail namespace. The user is still free to use it, but it's obvious that they should not and can't complain when you change it, breaking their code.

like image 38
deft_code Avatar answered Sep 29 '22 06:09

deft_code