Как использовать лямбда в качестве Делетера std::unique ptr?
Проверьте следующую надуманную программу:
#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;
}
С std:: конструктор функций manual, я думаю, что строительство std::function
объект может выбросить исключение, даже соотношение очень низкое:
UniPtr<int> func()
{
auto dealloc = [](int* p){delete p;};
return UniPtr<int>{alloc(), dealloc};
}
но если использовать указатель функции вместо
3 ответов
Я думаю, после ухода
func()
область,dealloc
объект должен быть освобожден, и на него нельзя ссылаться.
вам не нужно беспокоиться об этом. Да, лямбда-объект будет уничтожен, но указатель на функцию, возвращаемый функция преобразования указателя функции лямбды всегда действителен,он не будет болтаться.
значение, возвращаемое этой функцией преобразования является указателем на функцию с языка C++ связь, которая при вызове имеет тот же эффект, что и вызов оператора вызова функции объекта закрытия напрямую.
если вы определили UniPtr
as
template<typename T>
using UniPtr = std::unique_ptr<T, void(*)(T*)>;
тогда следующий код действителен, нет никаких проблем о времени жизни deleter
UniPtr<int> func()
{
auto dealloc = [](int* p){delete p;};
return UniPtr<int>{alloc(), dealloc};
}
Цитата N3337,expr.подтянутый.лямда/6
тип закрытия лямбда-выражение С лямбда-захват имеет публичный не виртуальный неявный
const
функцию преобразования в указатель на функцию, имеющую тот же параметр и возвращают типы как оператор вызова функции типа закрытия. значение, возвращаемое этой функцией преобразования, должно быть адресом функции это при вызове имеет тот же эффект, что и вызов оператора вызова функции типа закрытия.
таким образом, ваш deleter инициализируется указателем на функцию, которая остается действительной даже после возвращения из func
.
небольшое дополнение для реализации к предыдущим ответам...
template<typename T, typename D>
std::unique_ptr<T, D> make_unique_with_deleter(T* t, D d)
{
// granted copy elison since C++17
return std::unique_ptr<T, D> (t, d);
}
использование:
class A
{
};
auto up1 = make_unique_with_deleter(new A, [](A* a) {delete a; });
auto up2 = make_unique_with_deleter(std::fopen("something", "w"), std::fclose);
{
int any_value = 0;
// caution: only local use with lambda-capture, but possible
auto up3 = make_unique_with_deleter(new A, [any_value](A* a) {delete a; });
}
немного быстрое решение. Он работает в разных сценариях. Это позволяет избежать использования на std: function с его небольшими, но ненужными накладными расходами.