繁体   English   中英

如何使用lambda作为std :: unique_ptr的Deleter?

[英]How to use lambda as std::unique_ptr's Deleter?

检查以下人为的程序:

#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 :: function构造函数手册 ,我认为构造std::function对象可能会抛出异常,即使比率非常低:

UniPtr<int> func()
{
    auto dealloc = [](int* p){delete p;};

    return UniPtr<int>{alloc(), dealloc};
}

但是如果使用函数指针而不是std::function对象:

template<typename T>
using UniPtr = std::unique_ptr<T, void(*)(T*)>;

我想在离开func()范围后,应该释放dealloc对象,并且不能引用它。 如果我错了,请纠正我。 所以我能说出的唯一安全方法是定义一个全局dealloc函数:

void dealloc(int* p)
{
    delete p;
}

但我不喜欢这种方法。

根据先例说明,使用lambda作为std :: unique_ptr的Deleter并不是100%安全的方法,或者我误解了什么? 如何使用lambda作为std::unique_ptrDeleter

我想在离开func()范围后,应该释放dealloc对象,并且不能引用它。

你不必担心它。 是的lambda对象将被销毁,但lambda函数指针转换函数返回的函数指针始终有效,它不会被悬空。

此转换函数返回的值是指向具有C ++语言链接的函数的指针,该函数在调用时具有与直接调用闭包对象的函数调用操作符相同的效果。

如果您将UniPtr定义为

template<typename T>
using UniPtr = std::unique_ptr<T, void(*)(T*)>;

那么下面的代码是有效的,没有关于删除器的生命周期的担忧

UniPtr<int> func()
{
    auto dealloc = [](int* p){delete p;};
    return UniPtr<int>{alloc(), dealloc};
}

引用N3337, expr.prim.lambda / 6

没有lambda-capturelambda表达式的闭包类型有一个公共的非虚拟非显式const转换函数,用于指向具有与闭包类型的函数调用操作符相同的参数和返回类型的函数。 此转换函数返回的值应为函数的地址,该函数在调用时与调用闭包类型的函数调用运算符具有相同的效果。

因此,您的删除器正在使用指向函数的指针进行初始化,即使从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上的使用,只需要很少但不必要的开销。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM