复制std :: function有多贵?

Pet*_*lák 6 c++ c++11 std-function

虽然std::function是可移动的,但在某些情况下它是不可能的或不方便的.复制它有重大的惩罚吗?

它是否可能取决于捕获变量的大小(如果它是使用lambda表达式创建的)?它是依赖于实现的吗?

Yak*_*ont 11

std::function 通常实现为值语义,小缓冲区优化,虚拟分派,类型擦除类.

这意味着如果您的状态很小,则副本将不涉及堆分配(除了在状态的副本之外)和一些间接(以查找如何复制此特定状态).

如果您的状态很大(std::string例如,当前MSVC上大于2 秒),则需要额外的堆分配来存储状态.

这不是你想要以每像素每帧为基础做的事情,但它并不是非常昂贵.

您的特定编译器和库版本如何实现std::function可能会有所不同,但我不知道任何与上述不同的内容.

因此,在以下代码中:

std::function<std::string()> f = [s = "hello"s]{ return s; };
Run Code Online (Sandbox Code Playgroud)

复制f将涉及MSVC上的0堆分配.

然而,这段代码:

std::function<std::string()> g = [a = "a"s, b = "b"s, c = "c"s]{ return a+b+c; };
Run Code Online (Sandbox Code Playgroud)

确实需要堆分配来复制g.

(是的,这些都是非常愚蠢的功能对象.)

有效要求小缓冲区优化(SBO)应用于某些情况(函数指针,成员函数指针),std::function因为它们在分配内存时不会失败.一旦编写了一个SBO案例,使其更通用并不难,因此大多数std::function实现将"自身内部"的小对象和堆上的较大对象存储起来.

但是,此阈值未由标准指定,并且对性能成本很重要,因此如果性能非常重要,则必须进行配置以确保实现能够执行此操作.


Joh*_*nck 7

它确实依赖于实现.它还取决于你在什么地方存储std::function.它肯定不像简单地复制C风格的函数指针那么便宜.

最好的办法是让你尝试以清晰方便的方式编写代码,然后,如果运行速度不够快,请对其进行分析.如果您需要最终性能,您可能会发现std::function它根本不适合.

  • 通常有多种"清晰和方便"的方式(在某种程度上).使用或不使用`std :: function`可能意味着高级设计决策在后期阶段不容易逆转.了解定价很重要.恕我直言@Yakk的答案更有帮助. (2认同)