什么时候应该存储函数的引用或指针?
When should I store reference or pointer to functions?
我有一个向量 std::functions
Using Functors = std::vector<std::function<bool(int)>>;
Functors fs;
现在,如果我想向向量添加一个函数,我会这样做:
fs.emplace_back(
[](int v)->bool { return v > 1; }
)
我想知道当我声明 "Functors" 时,我是否应该使它指向 std::function 而不是原始的 std::function?这意味着,我将这样声明:
Using Functors = std::vector<
std::function<bool(int)>*
>; // note the last &
因此当我调用emplace_back时,我只是传递一个指针而不是复制?或者 lambda 闭包是可移动的?请在这里说明一下:我什么时候应该使用对 std::function 的引用?
首先,引用不能是模板的参数类型,因此您需要使用指针或std::reference_wrapper
代替:
std::vector<std::function<bool(int)>*>
std::vector<std::reference_wrapper<std::function<bool(int)>>>
在您的示例中,您的向量将无法保持 "references" 函数,因为您在 r 值上调用 emplace_back
。所以在这里,std::vector<std::function<bool(int)>>
对我来说似乎是一个很好的解决方案。
只需使用 std::vector<std::function<bool(int)>>
.
std::function
搬家的时候几乎总是便宜的。
为了不便宜,存储的函数对象必须 (A) 很小,(B) 有一个 no-except 移动构造函数,并且 (C) 移动起来很昂贵。
有意写这样一个对象并不难,但是不小心写一个对象就难了.
现在,标准没有强制要求多小;例如,对于 MSVC,他们将其设置为一或两个 std::string
的大小。
几乎可以肯定,与在此处使用值相比,管理原始指针的开销会使您的代码更糟且性能更低。一方面是因为修复原始指针错误会耗费脑力资源,另一方面是因为在自由存储上分配对象比 std::function
将几乎所有类型按数量级移动时所进行的分配成本更高。
平均而言,如果您使用 push_back
从空填充向量,则 std::vector
中的元素将移动固定次数(通常为 1-3 次),因为内存的要求托管呈指数增长,对象仅在需要调整大小时移动。
拥抱价值语义。
简而言之:永远不会!
(至少当你谈论 std::function<...>*
时不是 - 见下文)
如果你真的只想存储函数,做一个函数指针向量:
std::vector<bool(*)(int)> fs;
这也适用于在您的示例中使用空捕获的 lambda,因为它们隐式转换为函数指针。
如果您想存储任意有能力的对象,std::vector<std::function<bool(int)>>;
在 99.9% 的情况下应该没问题。很简单,你不太可能犯任何错误,也是最space有效的解决方案。
如果出于某种原因你真的想在堆上创建 std:: 函数对象,那么使用 unique_ptr:
std::vector<std::unique_ptr< std::function<bool(int)> >> fs;
fs.push_back( std::make_unique< std::function<bool(int)> >( [](int){ return true;}) );
这将确保您不会忘记删除这些对象。
解释:
也许我错了,但在我看来,您似乎误解了 std::function
是什么。它不是表示本机函数的 class,而是可以包装任何可调用对象(函数、函数对象、指向成员函数的指针 - 甚至指向成员的指针)的(相当重的)class。
- 存储函数指针既非常高效(它们只有 4-8 个字节大,对 copy/move 来说微不足道)又安全,因为函数的地址在整个程序中都是有效的(忽略共享的动态加载)库)。
- 通过
std::function
的间接访问增加了显着的开销(它们的大小通常是几个指针,而 move/copy 是实际函数)但它仍然是安全的。
- 存储指向
std::function
的原始指针通常需要在堆上创建该对象,这会带来额外的开销,但至少移动又便宜了。然而,它伴随着原始拥有指针的常见问题。因此 std::unique_ptr
的解决方案。
我有一个向量 std::functions
Using Functors = std::vector<std::function<bool(int)>>;
Functors fs;
现在,如果我想向向量添加一个函数,我会这样做:
fs.emplace_back(
[](int v)->bool { return v > 1; }
)
我想知道当我声明 "Functors" 时,我是否应该使它指向 std::function 而不是原始的 std::function?这意味着,我将这样声明:
Using Functors = std::vector<
std::function<bool(int)>*
>; // note the last &
因此当我调用emplace_back时,我只是传递一个指针而不是复制?或者 lambda 闭包是可移动的?请在这里说明一下:我什么时候应该使用对 std::function 的引用?
首先,引用不能是模板的参数类型,因此您需要使用指针或std::reference_wrapper
代替:
std::vector<std::function<bool(int)>*>
std::vector<std::reference_wrapper<std::function<bool(int)>>>
在您的示例中,您的向量将无法保持 "references" 函数,因为您在 r 值上调用 emplace_back
。所以在这里,std::vector<std::function<bool(int)>>
对我来说似乎是一个很好的解决方案。
只需使用 std::vector<std::function<bool(int)>>
.
std::function
搬家的时候几乎总是便宜的。
为了不便宜,存储的函数对象必须 (A) 很小,(B) 有一个 no-except 移动构造函数,并且 (C) 移动起来很昂贵。
有意写这样一个对象并不难,但是不小心写一个对象就难了.
现在,标准没有强制要求多小;例如,对于 MSVC,他们将其设置为一或两个 std::string
的大小。
几乎可以肯定,与在此处使用值相比,管理原始指针的开销会使您的代码更糟且性能更低。一方面是因为修复原始指针错误会耗费脑力资源,另一方面是因为在自由存储上分配对象比 std::function
将几乎所有类型按数量级移动时所进行的分配成本更高。
平均而言,如果您使用 push_back
从空填充向量,则 std::vector
中的元素将移动固定次数(通常为 1-3 次),因为内存的要求托管呈指数增长,对象仅在需要调整大小时移动。
拥抱价值语义。
简而言之:永远不会!
(至少当你谈论 std::function<...>*
时不是 - 见下文)
如果你真的只想存储函数,做一个函数指针向量:
std::vector<bool(*)(int)> fs;
这也适用于在您的示例中使用空捕获的 lambda,因为它们隐式转换为函数指针。
如果您想存储任意有能力的对象,std::vector<std::function<bool(int)>>;
在 99.9% 的情况下应该没问题。很简单,你不太可能犯任何错误,也是最space有效的解决方案。
如果出于某种原因你真的想在堆上创建 std:: 函数对象,那么使用 unique_ptr:
std::vector<std::unique_ptr< std::function<bool(int)> >> fs;
fs.push_back( std::make_unique< std::function<bool(int)> >( [](int){ return true;}) );
这将确保您不会忘记删除这些对象。
解释:
也许我错了,但在我看来,您似乎误解了 std::function
是什么。它不是表示本机函数的 class,而是可以包装任何可调用对象(函数、函数对象、指向成员函数的指针 - 甚至指向成员的指针)的(相当重的)class。
- 存储函数指针既非常高效(它们只有 4-8 个字节大,对 copy/move 来说微不足道)又安全,因为函数的地址在整个程序中都是有效的(忽略共享的动态加载)库)。
- 通过
std::function
的间接访问增加了显着的开销(它们的大小通常是几个指针,而 move/copy 是实际函数)但它仍然是安全的。 - 存储指向
std::function
的原始指针通常需要在堆上创建该对象,这会带来额外的开销,但至少移动又便宜了。然而,它伴随着原始拥有指针的常见问题。因此std::unique_ptr
的解决方案。