Check following contrived program:
#include <functional>
#include <memory>
template<typename T>
using UniPtr = std::unique_ptr<T, std::function<void(T*)>>;
int* alloc()
{
return new int;
}
UniPtr<int> func()
{
auto dealloc = [](int* p){delete p;};
return UniPtr<int>{alloc(), dealloc};
}
int main()
{
auto p = func();
return 0;
}
From std::function constructor manual, I think constructing std::function
object may throw exception, even the ratio is very low:
UniPtr<int> func()
{
auto dealloc = [](int* p){delete p;};
return UniPtr<int>{alloc(), dealloc};
}
But if using function pointer instead of std::function
object:
template<typename T>
using UniPtr = std::unique_ptr<T, void(*)(T*)>;
I think after leaving the func()
scope, the dealloc
object should be freed, and it can't be referenced. Please correct me if I am wrong. So the only safe method I can come out is defining a global dealloc
function:
void dealloc(int* p)
{
delete p;
}
But I don't like this method.
Based on precedent exposition, there is not 100% safe way to use lambda
as std::unique_ptr's Deleter, Or I misunderstand something? How to use lambda
as std::unique_ptr
's Deleter
?
I think after leaving the
func()
scope, thedealloc
object should be freed, and it can't be referenced.
You don't need to worry about it. Yes the lambda object will be destroyed, but the pointer to function returned by the lambda's function pointer conversion function is always valid, it won't become dangled.
The value returned by this conversion function is a pointer to a function with C++ language linkage that, when invoked, has the same effect as invoking the closure object's function call operator directly.
If you defined UniPtr
as
template<typename T>
using UniPtr = std::unique_ptr<T, void(*)(T*)>;
then the following code is valid, there are no concerns about the lifetime of the deleter
UniPtr<int> func()
{
auto dealloc = [](int* p){delete p;};
return UniPtr<int>{alloc(), dealloc};
}
Quoting N3337, expr.prim.lambda/6
The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit
const
conversion function to pointer to function having the same parameter and return types as the closure type's function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type's function call operator.
So your deleter is being initialized with a pointer to function, which remains valid even after you return from func
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With