김선달
김선달

Reputation: 1562

setting a custom deleter for std::unique_ptr with a non-static member function

How do I set a member function as a custom deleter for std::unique_ptr?

class foo{
public:
    foo() = default;
};

class fooDeleter{
public:
    fooDeleter() = default;
    
    void deleteFoo(foo* f) {
        cout << "deleting foo" << endl;
        delete f;
    }
};


int main() {
    fooDeleter* fd = new fooDeleter;
    using fptr = void (fooDeleter::*)(foo *f);
    fptr p = &fooDeleter::deleteFoo;
    
    std::unique_ptr<foo, fptr> fooptr{nullptr, (fd->*p)}; // syntax error

}

This works, but I can't figure out how to set a deleter...

foo* f = new foo;
(fd->*p)(f);

Upvotes: 0

Views: 586

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597205

Short answer - you can’t use a non-static method directly as a deleter. That is simply not what unique_ptr is expecting. You must use either:

  • a stand-alone function, or a static method.
  • a lambda.
  • a functor (an object with an operator() implemented).

For example:

class foo{
public:
    foo() = default;
};

void deleteFoo(foo* f) {
    cout << "deleting foo" << endl;
    delete f;
}

int main() {
    foo* f = new foo;
    std::unique_ptr<foo, decltype(&deleteFoo)> fooptr{f, &deleteFoo};
}
class foo{
public:
    foo() = default;
};

int main() {
    foo *f = new foo;
    auto deleter = [](foo* f){
        cout << “deleting foo” << endl;
        delete f;
    };
    std::unique_ptr<foo, decltype(deleter)> fooptr{f, deleter};
}
class foo{
public:
    foo() = default;
};

struct fooDeleter{
    void operator()(foo* f) {
        cout << "deleting foo" << endl;
        delete f;
    }
};

int main() {
    foo *f = new foo;
    std::unique_ptr<foo, fooDeleter> fooptr{f};
}

So, to have the deleter call a non-static method, you will have to wrap the call to the method inside one of those options. For instance, inside a custom functor that has a std::function member pointing at the method, and then the operator() can call that function. Or a lambda that captures the desired method and calls it. Or the functor returned by std::bind()'ing the method directly.

Upvotes: 1

Related Questions