Reputation: 4106
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 struct
s internally. Is there a way for the vector's elements (unique_ptr
s) 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
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
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