Resurrection
Resurrection

Reputation: 4106

How to avoid multiple deleter lambdas?

How to avoid multiple deleter lambdas with the following:

class A {};
class B : public A {};

auto del = [](A *p) { delete static_cast<A*>(p); }
std::vector<std::unique_ptr<A, void (*)(A*)>> vec;

vec.emplace_back(new B, del); //[1]
/* OR */
vec.emplace_back(new B, [](A *p) { delete static_cast<B*>(p); }); //[2]

So a class B that inherites A is put into a std::vector of std::unique_ptr<A> with custom deleter to properly invoke B's destructor. The deleter is a lambda and as far as I know doing this:

auto l1 = []{};
auto l2 = []{};

will yield two separate types even though the lambdas are the same since the lambdas are anonymous structs internally. Is there a way for the vector's elements (unique_ptrs) above to use only one lambda deleter for all of them? Perhaps by pre-declaring it and passing it to emplace_back like in [1]? Or is it pretty much the same as giving "new" lambda for every such call as in [2]?

Upvotes: 0

Views: 92

Answers (2)

SergeyA
SergeyA

Reputation: 62593

Deleters are copied into every unique_ptr by the constructor. It doesn't matter what you do with the lambda, every unique_ptr object will have a copy of it.

On a side note, I recommend against giving the type of the deleter as a function pointer. Instead use the decltype of lambda to avoid indirection call. Will save you some performance. Also, non-capturing lambda will likely take 0 bytes of storage for unique_ptr, while function pointer will take sizeof(void*) for every unique_ptr you have.

Upvotes: 1

Rakete1111
Rakete1111

Reputation: 48988

Well, to avoid the creation of a lot of lambdas in [2] (which would probably get optimized away anyway), [1] is a good way, although the lambda instance will get copied every time you add a new object (probably also optimized away, but I'm not sure).

But, if you don't want to deal with the hassle of passing the deleter every time you add a std::unique_ptr, make a functor:

struct deleter {
    void operator()(A *p) const noexcept { delete static_cast<B*(p); }
};

Because deleter is DefaultConstructible, the constructor of std::unique_ptr can create a deleter object itself, without you having to pass one. This is not possible with lambdas, as they are not DefaultConstructible.

Upvotes: 3

Related Questions