外贸做企业什么网站,深圳房地产最新消息,河南建筑信息一体化平台,wordpress配置伪静态页面std::function 是 C 标准库中的一个通用多态函数包装器。它可以存储、复制和调用任意可调用目标#xff08;函数、lambda 表达式、绑定表达式或其他函数对象#xff09;。 std::function 占有固定尺寸的内存#xff0c;这是因为它的实现方式决定了这一点。让我们深入探讨这一…std::function 是 C 标准库中的一个通用多态函数包装器。它可以存储、复制和调用任意可调用目标函数、lambda 表达式、绑定表达式或其他函数对象。 std::function 占有固定尺寸的内存这是因为它的实现方式决定了这一点。让我们深入探讨这一点。
std::function 的实现原理
std::function 通常使用类型擦除和小对象优化Small Object Optimization, SOO来实现这一点。
类型擦除
std::function 使用类型擦除来存储不同类型的可调用对象。这意味着它通过一个固定大小的存储空间和一个指向这些对象的虚表vtable来实现多态性。类型擦除允许 std::function 在运行时处理各种不同的类型而不需要知道这些类型的具体细节。
小对象优化SOO
对于小对象通常是指尺寸较小且可以直接存储在 std::function 内部的对象std::function 会直接在其内部存储这些对象。这避免了动态内存分配的开销。对于大对象超出 std::function 内部存储容量的对象std::function 会在堆上分配内存并在内部存储一个指向这些对象的指针。
std::function 为什么占有固定尺寸的内存
由于 std::function 使用了类型擦除和小对象优化其内部实现通常包含以下几个部分
一个指向实际存储对象的指针或存储小对象的内部缓冲区。一个指向虚表的指针用于多态调用。一些额外的元数据用于管理存储和调用。
这意味着无论存储的对象是多大或多小std::function 的实例总是占用固定大小的内存以包含这些指针和元数据。
内存布局的示例
假设我们有以下 std::function 声明
std::functionvoid() func;其内部可能包含如下内容 指向可调用对象的指针 或 内部缓冲区 如果对象足够小可以直接存储在内部缓冲区中。如果对象较大则存储一个指向该对象的指针。 虚表指针 虚表指针指向一组函数这些函数用于操作实际存储的对象调用、复制、销毁等。 元数据 用于管理存储对象的信息如对象大小、类型信息等。
无论我们存储的是一个普通函数指针一个小型 lambda 表达式还是一个大型函数对象std::function 实例的大小都是固定的。
示例代码
#include iostream
#include functionalvoid exampleFunction() {std::cout Hello from function! std::endl;
}int main() {// 存储普通函数指针std::functionvoid() func1 exampleFunction;// 存储lambda表达式std::functionvoid() func2 []() {std::cout Hello from lambda! std::endl;};// 存储大对象struct LargeFunctor {void operator()() const {std::cout Hello from large functor! std::endl;}int data[100];};std::functionvoid() func3 LargeFunctor();// 调用func1();func2();func3();std::cout Size of func1: sizeof(func1) std::endl;std::cout Size of func2: sizeof(func2) std::endl;std::cout Size of func3: sizeof(func3) std::endl;return 0;
}结果如下
Hello from function!
Hello from lambda!
Hello from large functor!
Size of func1: 32
Size of func2: 32
Size of func3: 32我们可以很明显得看出三个 std::function 对象大小都是一样的。 小总结 std::function 的大小是固定的因为它使用类型擦除和小对象优化来处理不同类型的可调用对象。这种固定大小的内存布局使得 std::function 可以有效地存储和管理多种不同类型的可调用对象同时提供统一的接口来调用这些对象。无论存储的对象是函数指针、小型 lambda 表达式还是大型函数对象std::function 的实例大小都是固定的。 std::function 实现运行时多态
运行时多态dynamic polymorphism指的是在程序运行时决定调用哪个具体的函数实现。通常通过虚函数和继承来实现。std::function 通过类型擦除和虚表机制提供了类似的功能使得它可以在运行时处理不同类型的可调用对象。
#include iostream
#include functional// 一个接受 std::functionvoid(int) 类型参数的函数
void invokeWithFive(const std::functionvoid(int) func) {func(5); // 调用传入的可调用对象并传递参数5
}int main() {// 使用普通函数指针void (*funcPtr)(int) [](int x) { std::cout Function pointer: x std::endl; };invokeWithFive(funcPtr);// 使用 lambda 表达式auto lambda [](int x) { std::cout Lambda: x std::endl; };invokeWithFive(lambda);// 使用函数对象struct Functor {void operator()(int x) const {std::cout Functor: x std::endl;}};Functor functor;invokeWithFive(functor);return 0;
}在运行时当我们调用 invokeWithFive(funcPtr)、invokeWithFive(lambda) 和 invokeWithFive(functor) 时std::function 会根据存储的不同可调用对象类型调用相应的实现。这种行为是运行时决定的因此属于运行时多态。