C++ std::ref 学习笔记

news/2025/2/23 22:29:59/文章来源:https://www.cnblogs.com/PHarr/p/18733020

std::reference_wrapper

std::reference_wrapper 是 C++ 标准库中一个特殊的类模板,它的核心目的是将引用包装成一个可以复制、可以赋值的对象。这种设计解决了 C++ 中普通引用(T&)的一些局限性,尤其是在需要传递或存储引用语义的场景中。

为什么需要 std::reference_wrapper

在 C++ 中,普通引用(T&)有以下限制

  • 不能直接存储在容器中:例如 std::vector<T&> 是无效的。
  • 不能直接复制或赋值:引用本身不是对象,只是一个别名。
  • 模板参数推导的局限性:当模板函数需要按值传递参数时,引用语义会丢失。

std::reference_wrapper<T> 通过将引用包装成一个对象,解决了这些问题:

  • 可以存储在容器中:例如 std::vector<std::reference_wrapper<T>> 是合法的。
  • 可以复制和赋值:它本身是一个对象,满足可复制构造和可复制赋值。
  • 隐式转换为原始引用:在使用时,可以无缝转换为 T&,保持引用语义。
特性 普通引用 (T&) std::reference_wrapper<T>
是否可复制
是否可存储到容器
是否隐式转换到 T& 本身就是 T& 是(通过隐式转换)
是否为对象 否(是别名) 是(是对象)

std::reference_wrapper 的核心特性

创建

std::reference_wrapper可由std::ref,std::cref创建

int a = 123;
auto ref1 = std::ref(a); // reference_wrapper<int>
auto ref2 = std::cref(a); // reference_wrapper<const int>

可复制、可赋值的对象

int a = 123;
int &ref1 = a;
int &ref2 = ref1; // ref2 仍然是 a 的引用,不是复制
auto ref3 = std::ref(a);
auto ref4 = ref3; // ref3, ref4 是两个不同的对象

隐式转换为原始引用

void print(int &x) { cout << x << "\n"; }int main() {int a = 123;auto ref_a = std::ref(a);print(ref_a); // 隐式转换为 int &
}

显式获取引

int a = 123;
auto ref_a = std::ref(a);
int& raw_ref = ref_a.get();  // 显式获取 int&

典型使用场景

将引用存储在容器中

int main() {int a = 1, b = 2, c = 3;cout << " " << a << " " << b << " " << c << "\n"; // 1 2 3std::vector<std::reference_wrapper<int>> vec = {a, b, c};vec[0].get() = 4;cout << " " << a << " " << b << " " << c << "\n"; // 4 2 3
}

与STL算法结合

int main() {int a = 2, b = 3, c = 1;std::vector<std::reference_wrapper<int>> vec = {a, b, c};for(auto i : vec) cout << i.get() << " \n"[i == vec.back()]; // 2 3 1std::ranges::sort(vec);for(auto i : vec) cout << i.get() << " \n"[i == vec.back()]; // 1 2 3
}

绑定到需要引用的函数

比如std::bind, std::thread这些函数默认是传值,如果你真的需要传引用可以用std::ref显示的传引用。

void foo(int &x) { cout << (++x) << " "; }int main() {int x{}, y{};auto f = std::bind(foo, x);auto g = std::bind(foo, std::ref(y));f(), f(), f(), cout << x << "\n"; // 1 2 3 0  g(), g(), g(), cout << y << "\n"; // 1 2 3 3
}

这种用户也可以使得与第三方库(如Boost库)保持行为一致,确保代码可移植性。

与不可复制的对象交互

int main() {std::unique_ptr<int> ptr(new int(123));auto foo = [](std::unique_ptr<int> &p) { cout << *p << "\n"; };foo(ptr); // 可以执行 p 直接引用 prt//    auto f = std::bind(foo, ptr); 
// 错误写法, 因为std::bind 要调用拷贝构造,但是unique_prt不能拷贝只能复制auto f = std::bind(foo, std::ref(ptr));f();
}

触发隐式类型转换的条件

  1. 传递给接受 T& 的函数参数

    void g(Example& ex) { ex.show(); }int main() {Example example;auto ref_ex = std::ref(example);g(ref_ex); // 正确:隐式转换为 Example&
    }
    
  2. 赋值给 T& 类型的变量

    Example example;
    auto ref_ex = std::ref(example);
    Example& ex_ref = ref_ex; // 隐式转换为 Example&
    ex_ref.show();            // 正确
    
  3. 在需要T& 的模板类型推导中

    template <typename T>
    void h(T& val) {  // T 推导为 Exampleval.show();
    }int main() {Example example;h(std::ref(example)); // 正确:T 推导为 Example,val 是 Example&
    }
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/888599.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工程管理(二)

工程模板介绍 DevEco Studio支持多种品类的应用/元服务开发,预置丰富的工程模板,可以根据工程向导轻松创建适应于各类设备的工程,并自动生成对应的代码和资源模板。同时,DevEco Studio还提供了多种编程语言供开发者进行应用/元服务开发,包括ArkTS、JS和C/C++。工程模板支持…

工程管理(一)

APP包结构 在进行应用/元服务开发前,开发者应该掌握应用/元服务的逻辑结构。 应用/元服务发布形态为APP Pack(Application Package),它是由一个或多个HAP(Harmony Ability Package)包以及描述APP Pack属性的pack.info文件组成。 一个HAP在工程目录中对应一个Module,它是…

包和抽象类介绍--java进阶day02

1.package包导包第二点需要注意 a包和b包都存有Student类,c包存有测试类,我们在c中创建Student对象,系统会询问你要哪个包的Student类,并自动帮你导包.在导完a包的学生类后,想要再次导入b包的学生类就不能再像之前那样导了全类名导包 通过带包名将b包重复的学生类导入2.抽…

2025.2.23(二进制等等)

平常我们生活使用的是十进制,在计算机中常用二进制等。 二进制是用0,1表示,逢二进1. 啊啊啊好难表达。 例如2在二进制中为10.哎上图片。。。。除2取余法,哎呀,不管了看图

Deveco Studio下载

Deveco Studio最新版本-下载中心根据自己的操作系统下载合适的版本即可 Windows环境 运行环境要求 为保证DevEco Studio正常运行,建议电脑配置满足如下要求:操作系统:Windows10 64位、Windows11 64位 内存:16GB及以上 硬盘:100GB及以上 分辨率:1280*800像素及以上安装Dev…

第一次作业—软件二次开发

一.项目来源 本次作业的项目来源是https://blog.csdn.net/m0_65636467/article/details/128069045?sharetype=blog&shareId=128069045&sharerefer=APP&sharesource=2301_80676751&sharefrom=link中的第7个C语言超市收款系统 二.运行环境和运行结果 1.运行环境…

《痞子衡嵌入式半月刊》 第 118 期

痞子衡嵌入式半月刊: 第 118 期这里分享嵌入式领域有用有趣的项目/工具以及一些热点新闻,农历年分二十四节气,希望在每个交节之日准时发布一期。 本期刊是开源项目(GitHub: JayHeng/pzh-mcu-bi-weekly),欢迎提交 issue,投稿或推荐你知道的嵌入式那些事儿。 上期回顾 :《…

【牛客训练记录】牛客周赛 Round 82

训练情况赛后反思 C题没想明白,但是发现了数列一定是不增加的,另外第一次出现的数字,那个位置就必须是那个数字,剩下可能是乘法原理之类的东西吧,但是没做出来 A题 判断字符串第一位和最后一位是否一致即可点击查看代码 #include <bits/stdc++.h> // #define int lo…

【Atcoder训练记录】AtCoder Beginner Contest 394

训练情况赛后反思 没在赛时打的,只做了签到TAT A题 统计字符串中 2 的数量,最后去掉其他的,只输出 2点击查看代码 #include <bits/stdc++.h> // #define int long long #define endl \nusing namespace std;void solve(){string s; cin>>s;int ans = 0;for(int …

DPDK收发包梳理

DPDKeal初始化 内存管理:大页,内存池 驱动开启调试信息 make config T=x86_64-native-linuxapp-gcc export EXTRA_CFLAGS=-O0 -g3 -ggdb make -j8 dpdk通过makefile编译 meson + ninja没学过,太麻烦了,可以参考dpdk17的文档,里面有介绍make编译方式。 https://doc.dpdk.or…

空气流量和空气压力参数解耦系统simulink建模与仿真

1.课题概述空气流量和空气压力参数解耦系统simulink建模与仿真,在许多系统中,空气流量(Q)和压力(P)之间存在耦合关系,这意味着改变一个参数会影响到另一个参数。通过解耦系统解决这种问题,从而提高系统的控制稳定性。2.系统仿真结果 (完整程序运行后无水印)3.核心程序…

【库】Coravel Cache缓存

Coravel 通过使高级应用程序功能(如任务/作业调度、排队、缓存、邮件(以及更多!))易于访问且易于使用,帮助开发人员快速启动并运行 .NET 应用程序。具有简单、富有表现力和直接的语法。Coravel非常简单,通过Rember来保存缓存数据,同时可以设定缓存的时长,然后通过Get来…