当前位置: 首页 > news >正文

C++23 std::move_only_function:一种仅可移动的可调用包装器 (P0288R9)

文章目录

    • 一、定义与基本概念
      • 1.1 定义
      • 1.2 基本概念
    • 二、特点
      • 2.1 仅可移动性
      • 2.2 支持多种限定符
      • 2.3 无`target_type`和`target`访问器
      • 2.4 强前置条件
    • 三、使用场景
      • 3.1 处理不可复制的可调用对象
      • 3.2 性能优化
      • 3.3 资源管理
    • 四、与其他可调用包装器的对比
      • 4.1 与`std::function`的对比
      • 4.2 与`std::function_ref`的对比
    • 五、总结

在C++的发展历程中,不断引入新的特性和工具来提升语言的性能和灵活性。C++23标准引入了 std::move_only_function,这是一种仅可移动的可调用包装器,为开发者处理不可复制的可调用对象提供了强大的支持。本文将详细介绍 std::move_only_function的定义、特点、使用场景以及与其他可调用包装器的对比。

一、定义与基本概念

1.1 定义

std::move_only_function是一个通用的多态函数包装器,定义于头文件<functional>中。它可以存储和调用任何可构造的(不要求是可移动构造的)可调用目标,包括函数、lambda表达式、bind表达式、其他函数对象,以及指向成员函数的指针和指向成员对象的指针。存储的可调用对象被称为std::move_only_function的目标。如果std::move_only_function不包含目标,则被称为空的。与std::function不同,调用空的std::move_only_function会导致未定义行为。

其模板定义如下:

// 主模板未定义
// template< class... >
// class move_only_function; // 各种特化版本
// template< class R, class... Args >
// class move_only_function< R( Args...)> ;
// template< class R, class... Args >
// class move_only_function< R( Args...) noexcept>;
// template< class R, class... Args >
// class move_only_function< R( Args...) &> ;
// template< class R, class... Args >
// class move_only_function< R( Args...) & noexcept>;
// template< class R, class... Args >
// class move_only_function< R( Args...) &&>;
// template< class R, class... Args >
// class move_only_function< R( Args...) && noexcept>;
// template< class R, class... Args >
// class move_only_function< R( Args...) const> ;
// template< class R, class... Args >
// class move_only_function< R( Args...) const noexcept>;
// template< class R, class... Args >
// class move_only_function< R( Args...) const &> ;
// template< class R, class... Args >
// class move_only_function< R( Args...) const & noexcept> ;
// template< class R, class... Args >
// class move_only_function< R( Args...) const &&>;
// template< class R, class... Args >
// class move_only_function< R( Args...) const && noexcept >;

1.2 基本概念

std::move_only_function满足MoveConstructibleMoveAssignable的要求,但不满足CopyConstructibleCopyAssignable。这意味着它只能通过移动操作进行构造和赋值,不能进行复制操作。这种设计使得std::move_only_function能够处理那些不可复制的可调用对象,例如捕获了std::unique_ptr的lambda表达式。

二、特点

2.1 仅可移动性

std::move_only_function的核心特点是仅可移动。这是为了处理那些不可复制的可调用对象而设计的。在C++中,有些对象由于其资源管理的特性(如std::unique_ptr)不能被复制,只能被移动。std::move_only_function允许我们将这些不可复制的可调用对象存储在一个包装器中,从而方便地进行传递和调用。

2.2 支持多种限定符

std::move_only_function支持模板参数中提供的每一种可能的cv限定符(不包括volatile)、引用限定符和noexcept说明符的组合。这些限定符和说明符(如果有的话)会被添加到其operator()中。这使得std::move_only_function能够精确地匹配不同类型的可调用对象,提供了更高的灵活性。

2.3 无target_typetarget访问器

std::function不同,std::move_only_function没有target_typetarget访问ors。这是根据用户和实现者的需求做出的设计决策。移除这些访问器可以简化实现,并避免一些潜在的问题。

2.4 强前置条件

调用std::move_only_function时具有强前置条件。如果std::move_only_function为空,则调用它会导致未定义行为。这要求开发者在调用之前确保std::move_only_function包含有效的目标。

三、使用场景

3.1 处理不可复制的可调用对象

当需要处理捕获了不可复制对象(如std::unique_ptr)的lambda表达式时,std::move_only_function是一个很好的选择。以下是一个示例:

#include <iostream>
#include <functional>
#include <memory>int main() {auto ptr = std::make_unique<int>(42);// 捕获std::unique_ptr的lambda表达式auto lambda = [ptr = std::move(ptr)]() {std::cout << *ptr << std::endl;};// 使用std::move_only_function存储lambda表达式std::move_only_function<void()> func = std::move(lambda);func(); // 调用存储的lambda表达式return 0;
}

在这个示例中,lambda表达式捕获了一个std::unique_ptr,由于std::unique_ptr是不可复制的,因此不能使用std::function来存储这个lambda表达式。而std::move_only_function可以通过移动操作来存储这个lambda表达式,从而实现对不可复制可调用对象的处理。

3.2 性能优化

在某些情况下,使用std::move_only_function可以避免不必要的复制操作,从而提高性能。例如,当需要将一个可调用对象从一个函数传递到另一个函数时,如果这个可调用对象是不可复制的,使用std::move_only_function可以通过移动操作来传递,避免了复制的开销。

3.3 资源管理

std::move_only_function可以用于管理资源的生命周期。例如,在一个函数中创建一个可调用对象,该对象持有一些资源(如文件句柄、网络连接等),并将其存储在std::move_only_function中。当std::move_only_function被销毁时,其持有的可调用对象也会被销毁,从而自动释放资源。

四、与其他可调用包装器的对比

4.1 与std::function的对比

  • 复制性std::function是可复制的,而std::move_only_function是仅可移动的。这意味着std::function可以存储和复制任何可复制的可调用对象,而std::move_only_function专门用于处理不可复制的可调用对象。
  • 性能:由于std::move_only_function避免了复制操作,在处理不可复制对象时可能具有更好的性能。而std::function在复制操作上可能会有一定的开销。
  • 功能完整性std::function具有target_typetarget访问ors,可以用于获取存储的可调用对象的类型和指针。而std::move_only_function没有这些访问ors,这使得它的实现更加简单,但也限制了一些功能。

4.2 与std::function_ref的对比

  • 所有权std::function_ref是一个轻量级的引用包装器,它不拥有可调用对象的所有权,只是对可调用对象的一个引用。而std::move_only_function拥有可调用对象的所有权,当std::move_only_function被销毁时,其持有的可调用对象也会被销毁。
  • 生命周期管理:由于std::function_ref只是一个引用,它要求被引用的可调用对象的生命周期必须长于std::function_ref本身。而std::move_only_function对可调用对象的生命周期有完全的控制权。
  • 可移动性std::function_ref是可复制的,而std::move_only_function是仅可移动的。这使得std::function_ref更适合作为函数参数传递,而std::move_only_function更适合用于存储和管理不可复制的可调用对象。

五、总结

std::move_only_function是C++23标准引入的一个重要特性,它为开发者提供了一种处理不可复制可调用对象的有效方式。通过其仅可移动的特性、对多种限定符的支持以及强前置条件等特点,std::move_only_function在处理复杂的可调用对象和优化性能方面具有很大的优势。在实际开发中,当需要处理不可复制的可调用对象时,不妨考虑使用std::move_only_function来提升代码的性能和灵活性。

相关文章:

  • 常用第三方库:sqflite数据库应用
  • 深入解析MyBatis-Plus中的lambdaUpdate与lambdaQuery
  • clickhouse#复制修改数据
  • 深度解析:Web Crawling与Web Scraping的区别与联系
  • 玩转OurBMC第十八期:iKVM特性浅讲
  • Pycharm(十七)生成器
  • 案例分享(九):Hadoop分布式集群部署(三节点)
  • 基于STM32、HAL库的HX710A模数转换器ADC驱动程序设计
  • 系统架构师---基于规则的系统架构
  • 海关 瑞数 后缀分析 rs
  • java16
  • AI赋能守护行车安全新防线,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建驾驶车辆场景下驾驶员疲劳分心驾驶行为智能检测预警系统
  • 泰迪杯实战案例超深度解析:运输车辆安全驾驶行为分析与安全评价系统设计
  • 关于IDEA的循环依赖问题
  • AI 发展历史与关键里程碑_附AI 模型清单及典型应用场景以及物流自动化适合的模型选择
  • 探针台在光电行业的应用
  • On the Biology of a Large Language Model——Claude团队的模型理解文章【论文阅读笔记】其二——数学计算部分
  • STM32 CAN通信 HAL库实战教程:从零到测试成功
  • JavaScript 解构赋值(下):对象解构与高级应用
  • 爬虫技术入门:基本原理、数据抓取与动态页面处理
  • 王羲之《丧乱帖》在日本流传了1300年,将在大阪展23天
  • 本周看啥|在电影院里听民谣,听摇滚,燥起来吧
  • 杭州发布最新“独角兽企业”榜单,“六小龙”中5家已晋级
  • 神十九乘组视频祝福第十个中国航天日,展望中华民族登月梦圆
  • 上海体育消费节将从5月持续至11月,推出运动装备商品促销活动
  • GDP十强省份“一季报”出炉,湖北领跑