虽然std::function
是可移动的,但在某些情况下不可能或不方便。复制它有重大的惩罚吗?复制std ::函数的代价是多少?
它可能取决于捕获的变量的大小(如果它是使用lambda表达式创建的)?它依赖于实现吗?
虽然std::function
是可移动的,但在某些情况下不可能或不方便。复制它有重大的惩罚吗?复制std ::函数的代价是多少?
它可能取决于捕获的变量的大小(如果它是使用lambda表达式创建的)?它依赖于实现吗?
它确实取决于实现。这也取决于你在std::function
中存储的是什么。它肯定不像简单复制一个C风格的函数指针那么便宜。
最好的办法就是让你按照你找到清晰方便的方式来编写代码,然后,如果运行速度不够快,请对其进行配置。如果你需要最终的表现,你可能会发现std::function
根本不适合。
通常有多种“清晰和方便”的方式(在某种程度上)。使用或不使用'std :: function'可能意味着高层次的设计决策,在后期阶段不容易反转。了解定价很重要。恕我直言@雅克的答案更有帮助。 –
std::function
通常实现为值语义,小缓冲区优化,虚拟调度,类型擦除类。
这意味着如果你的状态很小,副本将不涉及堆分配(除了在状态的副本内)和一些间接寻求(找到如何复制这个特定的状态)。
如果您的状态很大(例如,在当前MSVC上大于两个std::string
s),则需要额外的堆分配来存储状态。
这不是你想要在每个像素每帧的基础上做的事情,但它并不是非常昂贵。
您的特定编译器和库版本如何实现std::function
可能会有所不同,但我不知道与上述显着不同。
那么,在下面的代码:
std::function<std::string()> f = [s = "hello"s]{ return s; };
复制f
将涉及MSVC 0堆分配。
然而,这段代码:
std::function<std::string()> g = [a = "a"s, b = "b"s, c = "c"s]{ return a+b+c; };
确实需要一个堆分配复制g
。
(是的,这两个是非常愚蠢的函数对象。)
还有就是小缓冲区优化(SBO)在std::function
应用于某些情况下(函数指针,成员函数指针)有效需求因为他们预计不会分配内存失败。一旦你写了一个SBO的情况下,使它更通用并不难,所以大多数std::function
实现存储“自己内部”的小对象和堆上的大对象。
但是,此阈值并未由标准规定,并且对于性能成本非常重要,因此如果性能非常重要,则必须进行配置以确保您的实施能够实现。
显然,如果您的函数对象包含捕获的对象,则复制惩罚将与捕获的对象的数量成比例。 –
作为一个方面说明,因为'std :: function'必须复制给定的目标,所以如果性能是你喜欢的,它不是最好的对象。 –
测量它。即使它应该是独立于实现(它不是),它仍然取决于实现的质量,并且您需要进行测量。即使它取决于捕获的变量,除非您测量,否则您将不会知道_how_因它们的类型/大小/数量而异。 – Useless