如何实现 std::function:类型擦除和堆分配
std::function 的一个关键实现细节是它的能力包装任何可调用对象,包括 lambda 表达式。虽然 lambda 的大小不同,但 std::function 保持固定大小。这是通过一种称为类型擦除的技术来实现的。
举一个 std::function
struct callable_base { virtual int operator()(double d) = 0; virtual ~callable_base() {} }; template <typename F> struct callable : callable_base { F functor; callable(F functor) : functor(functor) {} virtual int operator()(double d) { return functor(d); } };
这里,std::function 成立一个 unique_ptr 到一个基本的 callable_base 类型。对于所使用的每个唯一函子,派生类型可调用
std::function 的副本会触发内部可调用对象的副本,而不是共享状态。从可变捕获变量的值递增的测试中可以明显看出这一点:
int value = 5; std::function<void()> f1 = [=]() mutable { std::cout << value++ << '\n'; }; std::function<void()> f2 = f1; // Prints 5 f1(); // Prints 5 (copy of mutable state) f2();
因此,std::function 使用类型擦除和堆分配有效地包装不同大小的可调用对象。堆分配用于根据包装的可调用实例化动态类型,确保 std::function 本身的固定大小。
以上是尽管包装了不同大小的可调用对象,但'std::function”如何实现固定大小?的详细内容。更多信息请关注PHP中文网其他相关文章!